sinatra-authentication-nedludd 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ pkg/
2
+ *.swp
3
+ *.db
4
+ *.tct
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2009-04-06
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest ADDED
@@ -0,0 +1,26 @@
1
+ History.txt
2
+ Manifest
3
+ Rakefile
4
+ TODO
5
+ lib/models/abstract_user.rb
6
+ lib/models/datamapper_user.rb
7
+ lib/models/dm_adapter.rb
8
+ lib/models/mongomapper_user.rb
9
+ lib/models/mm_adapter.rb
10
+ lib/models/rufus_tokyo_user.rb
11
+ lib/models/tc_adapter.rb
12
+ lib/sinatra-authentication.rb
13
+ lib/views/edit.haml
14
+ lib/views/index.haml
15
+ lib/views/login.haml
16
+ lib/views/show.haml
17
+ lib/views/signup.haml
18
+ readme.markdown
19
+ test/datamapper_test.rb
20
+ test/lib/dm_app.rb
21
+ test/lib/helper.rb
22
+ test/lib/tc_app.rb
23
+ test/lib/test.db
24
+ test/lib/users.tct
25
+ test/route_tests.rb
26
+ test/rufus_tokyo_test.rb
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+
7
+ Jeweler::Tasks.new do |gemspec|
8
+ gemspec.name = 'sinatra-authentication-nedludd'
9
+ gemspec.version = '0.0.1'
10
+ gemspec.description = "Simple authentication plugin for sinatra."
11
+ gemspec.summary = "Simple authentication plugin for sinatra."
12
+ gemspec.homepage = "http://github.com/nedludd/sinatra-authentication"
13
+ gemspec.author = ["Max Justus Spransy" "Tim Hermans"]
14
+ gemspec.email = ["maxjustus@gmail.com" "thermans@gmail.com"]
15
+ gemspec.add_dependency "sinatra"
16
+ gemspec.add_dependency "dm-core"
17
+ gemspec.add_dependency "dm-migrations"
18
+ gemspec.add_dependency "dm-validations"
19
+ gemspec.add_dependency "dm-timestamps"
20
+ gemspec.add_dependency "rack-flash"
21
+ end
22
+ Jeweler::GemcutterTasks.new
23
+ rescue LoadError
24
+ puts "Jeweler (or a dependency) not available. Install it first!"
25
+ end
26
+
27
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
28
+
29
+ require 'rake/testtask'
30
+
31
+ Rake::TestTask.new do |t|
32
+ t.libs << "test"
33
+ t.test_files = FileList['test/mongomapper_test.rb']
34
+ t.verbose = true
35
+ end
36
+
data/TODO ADDED
@@ -0,0 +1,53 @@
1
+ TODO:
2
+ ensure all calls to new in adaptors are equivelant to "find or create by"
3
+ - this is done in the Tc adaptor, and essentially works in Dm adaptor
4
+ because I validate the uniqueness of email
5
+ implement some way to allow for the creation of users with different
6
+ permission levels in an untamperable manner. Perhaps with some secret key
7
+ that must be sent in the form
8
+ - look at other permissions systems for some feature ideas
9
+ - add a config method that you pass a hash for configuring it's behavior
10
+ - secret signup urls
11
+ - account activation through email
12
+
13
+ - ?implement a session store which isn't cookie based
14
+ - turn on sessions unless they're already on
15
+ - randomize the session key on every installation?
16
+ - clean up adapters
17
+ - write simple attribute declaration method for TcUser
18
+ - condense the adapters down to the simplest solution that could possibly work
19
+ - right now it's like I have two seperate goals, both which are important
20
+ one is to write a simple ORM for rufus tokyo, the other is to create a simple adapter
21
+ for different database backends. I think it would be better if I made the datamapper adapter more abstract
22
+ and the api simpler, and then changed the way the controllers and views work to interface with the more abstract and simpler adapter.
23
+ maybe make the adapter class called UserAdapter, and then TkUser and DmUser become User. All my controller method calls go to UserAdapter
24
+ but then for people wanting to talk to the model, they just use User, since they aren't dealing with multiple backends and thus don't need
25
+ a creepy adapter.
26
+
27
+ - make site admin work the same for dm and tc, because I like how permission == -2 is site admin, then you could set a user as site admin instead of it being limited to the first user created
28
+ and they wouldn't be deletable.
29
+ or maybe I just make a heirarchy for that so users with lower permissions can't delete users with higher.
30
+ just remember, this is supposed to be a simple authentication solution
31
+
32
+
33
+ - for the User adapter
34
+ - add pagination to all
35
+ - serious cleanup of rufus_tokyo_user.rb
36
+ - add virtual attribute declaration
37
+ - add validations
38
+ - remove the object syntax method_missing? and stick to hash accessors?
39
+ - or rather then use method missing, dynamically create class methods based in the contents of the hash?
40
+ - or create a validator tool for hashes. hash.valid?
41
+ - change User to AbstractUser and DmUser and TcUser to User
42
+
43
+ - add error messages for failed logins and stuff
44
+
45
+ - PROBLEM the way I have method missing working right now, it doesn't behave the same way I've documented, since I use it for attributes
46
+ - throw configuration errors on startup
47
+ - investigate why sinatra_auth doesn't seem to work unless it's the last thing required..
48
+
49
+ - add facebook connect
50
+ - using facebooker and frankie
51
+ - using the same method as datamapper vs tokyo in that the functionality is only included if the libraries are required
52
+ before sinatra_auth is.
53
+ - when a user signs in using facebook and doesn't have an email specified, an email field is included in the edit form.
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require 'sinatra'
3
+ require 'haml'
4
+ require 'dm-core'
5
+ require 'dm-migrations'
6
+ require 'rack-flash'
7
+ require 'sinatra-authentication'
8
+
9
+ class DmUser
10
+ property :name, String
11
+ end
12
+
13
+ DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/test.db")
14
+ DataMapper.auto_migrate!
15
+
16
+ set :sinatra_authentication_view_path, Pathname(__FILE__).dirname.expand_path + "extend_views/"
17
+ use Rack::Session::Cookie, :secret => "heyhihello"
18
+ use Rack::Flash
19
+
20
+ set :environment, 'development'
21
+ set :public, 'public'
22
+ set :views, 'views'
23
+
24
+ get '/' do
25
+ haml "= render_login_logout", :layout => :layout
26
+ end
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'sinatra'
3
+ require 'haml'
4
+ require 'sinbook'
5
+ require 'dm-core'
6
+ require 'dm-migrations'
7
+ require 'sinatra-authentication'
8
+
9
+ facebook do
10
+ api_key 'aa2db1b96cb7b57f0c5b1d4d3d8f0a22'
11
+ secret '21d94ee63969ae3b3f833689838ca00f'
12
+ app_id 48652736613
13
+ url 'peoplewithjetpacks.com:4568/'
14
+ callback 'peoplewithjetpacks.com:4568/'
15
+ end
16
+
17
+ set :port, 4568
18
+
19
+ DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/test.db")
20
+ DataMapper.auto_migrate!
21
+
22
+ use Rack::Session::Cookie, :secret => "heyhihello"
23
+
24
+ set :environment, 'development'
25
+ set :public, 'public'
26
+ set :views, 'views'
27
+
28
+ get '/' do
29
+ haml :main
30
+ end
31
+
32
+ get '/test' do
33
+ login_required
34
+ 'hihihi'
35
+ end
36
+
37
+ __END__
38
+
39
+ @@ layout
40
+ %html{:xmlns=>"http://www.w3.org/1999/xhtml", :'xmlns:fb'=>"http://www.facebook.com/2008/fbml"}
41
+ %head
42
+ %title Welcome to my Facebook Connect website!
43
+ %script{:type => 'text/javascript', :src => 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php/en_US'}
44
+ %body
45
+ = render_login_logout
46
+ = yield
47
+ :javascript
48
+ FB.init("#{fb.api_key}", "/receiver")
49
+
50
+ @@ main
51
+ - if fb[:user]
52
+ Hi,
53
+ %fb:profile-pic{:uid => fb[:user]}
54
+ %fb:name{:uid => fb[:user], :useyou => 'false', :firstnameonly => 'true'}
55
+ !
56
+
@@ -0,0 +1,42 @@
1
+ #sinatra_authentication
2
+ #sinatra_authentication_flash= flash[:notice]
3
+ %h1
4
+ Edit
5
+ - if @user.id == current_user.id
6
+ account
7
+ - else
8
+ - if @user.email
9
+ = @user.email
10
+ - elsif @user.fb_uid
11
+ <fb:name uid=#{@user.fb_uid} linked='false' />
12
+ - else
13
+ account
14
+ %form{:action => "/users/#{@user.id}/edit", :method => "post"}
15
+ .field
16
+ .label
17
+ %label{:for => "user_email"} Email
18
+ %input{ :id => "user_email", :name => "user[email]", :size => 30, :type => "text", :value => @user.email }
19
+ .field
20
+ .label
21
+ %label{:for => "user_password"} New password
22
+ %input{ :id => "user_password", :name => "user[password]", :size => 30, :type => "password" }
23
+ .field
24
+ .label
25
+ %label{:for => "user_password_confirmation"} Confirm
26
+ %input{ :id => "user_password_confirmation", :name => "user[password_confirmation]", :size => 30, :type => "password" }
27
+ -# don't render permission field if admin and editing yourself so you don't shoot yourself in the foot
28
+ - if current_user.admin? && current_user.id != @user.id
29
+ .field
30
+ .label
31
+ %label{:for => 'permission_level'} Permission level
32
+ %select{ :id => "permission_level", :name => "user[permission_level]" }
33
+ %option{:value => -1, :selected => @user.admin?}
34
+ Admin
35
+ %option{:value => 1, :selected => @user.permission_level == 1}
36
+ Authenticated user
37
+ .buttons
38
+ %input{ :value => "Update", :type => "submit" }
39
+ - if Sinatra.const_defined?('FacebookObject')
40
+ - unless @user.fb_uid
41
+ |
42
+ = render_facebook_connect_link('Link account with Facebook')
@@ -0,0 +1,31 @@
1
+ #sinatra_authentication
2
+ %h1.page_title Users
3
+ %table
4
+ %tr
5
+ %th
6
+ - if current_user.admin?
7
+ %th permission level
8
+ - @users.each do |user|
9
+ %tr
10
+ %td
11
+ - if user.email
12
+ = user.email
13
+ - elsif user.fb_uid
14
+ <fb:name uid=#{user.fb_uid} />
15
+ - else
16
+ "user #{user.id}"
17
+ - if current_user.admin?
18
+ %td= user.permission_level
19
+ %td
20
+ = user.name
21
+ %td
22
+ %a{:href => "/users/#{user.id}"} show
23
+ - if current_user.admin?
24
+ %td
25
+ %a{:href => "/users/#{user.id}/edit"} edit
26
+ %td
27
+ -# this doesn't work for tk
28
+ - if !user.site_admin?
29
+ %a{:href => "/users/#{user.id}/delete", :onclick => "return confirm('you sure?')"} delete
30
+ - else
31
+ site admin
@@ -0,0 +1,21 @@
1
+ #sinatra_authentication
2
+ #sinatra_authentication_flash= flash[:notice]
3
+ %h1.page_title Login
4
+ %form{:action => "/login", :method => "post"}
5
+ .field
6
+ .label
7
+ %label{:for => "user_email'"} Email
8
+ %input{:id => "user_email", :name => "email", :size => 30, :type => "text"}
9
+ .field
10
+ .label
11
+ %label{:for => "user_password"} Password
12
+ %input{:id => "user_password", :name => "password", :size => 30, :type => "password"}
13
+ .buttons
14
+ %input{:value => "login", :type => "submit"}
15
+ %a{:href => "/signup", :class => 'sinatra_authentication_link'}
16
+ Signup
17
+ - if Sinatra.const_defined?('FacebookObject')
18
+ .third_party_signup
19
+ %h3.section_title One click login:
20
+ .login_link.facebook_login
21
+ = render_facebook_connect_link('Login using facebook', :size => 'large')
@@ -0,0 +1,9 @@
1
+ #sinatra_authentication
2
+ %h1.page_title
3
+ - if @user.email
4
+ = @user.email
5
+ - elsif @user.fb_uid
6
+ <fb:name uid=#{@user.fb_uid} linked='false' />
7
+ - if current_user.admin?
8
+ %h2 permission level
9
+ = @user.permission_level
@@ -0,0 +1,30 @@
1
+ %h1 This view is overridden
2
+ #sinatra_authentication
3
+ #sinatra_authentication_flash= flash[:notice]
4
+ %h1.page_title Signup
5
+ %form{:action => "/signup", :method => "post"}
6
+ .field
7
+ .label
8
+ %label{:for => "user_email"} Email
9
+ %input{ :id => "user_email", :name => "user[email]", :size => 30, :type => "text" }
10
+ .field
11
+ .label
12
+ %label{:for => "user_password"} Password
13
+ %input{ :id => "user_password", :name => "user[password]", :size => 30, :type => "password" }
14
+ .field
15
+ .label
16
+ %label{:for => "user_name"} Name
17
+ %input{ :id => "user_name", :name => "user[name]", :size => 30, :type => "text" }
18
+ .field
19
+ .label
20
+ %label{:for => "user_password_confirmation"} Confirm Password
21
+ %input{ :id => "user_password_confirmation", :name => "user[password_confirmation]", :size => 30, :type => "password" }
22
+ .buttons
23
+ %input{ :value => "Create account", :type => "submit" }
24
+ %a{:href => "/login", :class => 'sinatra_authentication_link'}
25
+ Login
26
+ - if Sinatra.const_defined?('FacebookObject')
27
+ .third_party_signup
28
+ %h3.section_title One click signup:
29
+ .login_link.facebook_login
30
+ = render_facebook_connect_link('Signup using facebook', :size => 'large')
data/example/mm_app.rb ADDED
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'sinatra/base'
3
+ require 'haml'
4
+ require 'mongo_mapper'
5
+ require 'sinatra-authentication'
6
+
7
+ logger = Logger.new($stdout)
8
+ MongoMapper.connection = Mongo::Connection.new('db.mongohq.com', 27017, :logger => logger)
9
+ MongoMapper.database = "fdbk"
10
+ MongoMapper.database.authenticate(ENV['mongohq_user'], ENV['mongohq_pass'])
11
+
12
+ class TestApp < Sinatra::Base
13
+ use Rack::Session::Cookie, :secret => "heyhihello"
14
+
15
+ set :environment, 'development'
16
+ set :public, 'public'
17
+ set :views, 'views'
18
+
19
+ get '/' do
20
+ haml "= render_login_logout", :layout => :layout
21
+ end
22
+ end
data/example/tc_app.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'sinatra'
3
+ require 'haml'
4
+ require 'rufus/tokyo'
5
+ require 'sinatra-authentication'
6
+
7
+ use Rack::Session::Cookie, :secret => "heyhihello"
8
+ TcUserTable.cabinet_path = File.dirname(__FILE__)
9
+
10
+ set :environment, 'development'
11
+ set :public, 'public'
12
+ set :views, 'views'
13
+
14
+ get '/' do
15
+ haml "= render_login_logout", :layout => :layout
16
+ end
@@ -0,0 +1,62 @@
1
+ require 'rubygems'
2
+ require 'haml'
3
+ require 'sinbook'
4
+ require 'rufus/tokyo'
5
+ require 'sinatra'
6
+ require 'sinatra-authentication'
7
+
8
+ use Rack::Session::Cookie, :secret => "heyhihello"
9
+ TcUserTable.cabinet_path = File.dirname(__FILE__)
10
+
11
+ facebook do
12
+ api_key 'aa2db1b96cb7b57f0c5b1d4d3d8f0a22'
13
+ secret '21d94ee63969ae3b3f833689838ca00f'
14
+ app_id 48652736613
15
+ url 'peoplewithjetpacks.com:4568/'
16
+ callback 'peoplewithjetpacks.com:4568/'
17
+ end
18
+
19
+ set :port, 4568
20
+
21
+ get '/' do
22
+ haml :main
23
+ end
24
+
25
+ get '/test' do
26
+ login_required
27
+ 'hihihi'
28
+ end
29
+
30
+ __END__
31
+
32
+ @@ layout
33
+ %html{:xmlns=>"http://www.w3.org/1999/xhtml", :'xmlns:fb'=>"http://www.facebook.com/2008/fbml"}
34
+ %head
35
+ %title Welcome to my Facebook Connect website!
36
+ %script{:type => 'text/javascript', :src => 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php/en_US'}
37
+ %script{:type => 'text/javascript', :src => 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js'}
38
+ :javascript
39
+ $(document).ready(function(){
40
+ /* test facebook crap works with ajax */
41
+ $('.sinatra-authentication-login').click(function(){
42
+ $.get($(this).attr('href'), {}, function(data){
43
+ $('#test_box').html(data);
44
+ });
45
+ return false;
46
+ });
47
+ });
48
+ %body
49
+ = render_login_logout
50
+ = yield
51
+ :javascript
52
+ FB.init("#{fb.api_key}", "/receiver")
53
+ #test_box
54
+
55
+ @@ main
56
+ - if fb[:user]
57
+ Hi,
58
+ %fb:profile-pic{:uid => fb[:user]}
59
+ %fb:name{:uid => fb[:user], :useyou => 'false', :firstnameonly => 'true'}
60
+ !
61
+ %br/
62
+