sinatra-authentication-gogolok 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/History.txt +4 -0
- data/Manifest +24 -0
- data/Rakefile +34 -0
- data/TODO +53 -0
- data/lib/models/abstract_user.rb +49 -0
- data/lib/models/datamapper_user.rb +38 -0
- data/lib/models/dm_adapter.rb +44 -0
- data/lib/models/rufus_tokyo_user.rb +146 -0
- data/lib/models/tc_adapter.rb +73 -0
- data/lib/sinatra-authentication.rb +206 -0
- data/lib/views/edit.haml +21 -0
- data/lib/views/index.haml +23 -0
- data/lib/views/login.haml +10 -0
- data/lib/views/show.haml +6 -0
- data/lib/views/signup.haml +13 -0
- data/readme.markdown +92 -0
- data/sinatra-authentication.gemspec +80 -0
- data/test/datamapper_test.rb +5 -0
- data/test/lib/dm_app.rb +18 -0
- data/test/lib/helper.rb +9 -0
- data/test/lib/tc_app.rb +16 -0
- data/test/route_tests.rb +29 -0
- data/test/rufus_tokyo_test.rb +5 -0
- metadata +122 -0
data/.gitignore
ADDED
data/History.txt
ADDED
data/Manifest
ADDED
@@ -0,0 +1,24 @@
|
|
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/rufus_tokyo_user.rb
|
9
|
+
lib/models/tc_adapter.rb
|
10
|
+
lib/sinatra-authentication.rb
|
11
|
+
lib/views/edit.haml
|
12
|
+
lib/views/index.haml
|
13
|
+
lib/views/login.haml
|
14
|
+
lib/views/show.haml
|
15
|
+
lib/views/signup.haml
|
16
|
+
readme.markdown
|
17
|
+
test/datamapper_test.rb
|
18
|
+
test/lib/dm_app.rb
|
19
|
+
test/lib/helper.rb
|
20
|
+
test/lib/tc_app.rb
|
21
|
+
test/lib/test.db
|
22
|
+
test/lib/users.tct
|
23
|
+
test/route_tests.rb
|
24
|
+
test/rufus_tokyo_test.rb
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
#Echoe.new('sinatra-authentication', '0.0.5') do |p|
|
5
|
+
# p.description = "Simple authentication plugin for sinatra."
|
6
|
+
# p.url = "http://github.com/maxjustus/sinatra-authentication"
|
7
|
+
# p.author = "Max Justus Spransy"
|
8
|
+
# p.email = "maxjustus@gmail.com"
|
9
|
+
# p.ignore_pattern = []
|
10
|
+
# p.development_dependencies = ["sinatra", "dm-core", "dm-timestamps", "dm-validations", "rufus-tokyo"]
|
11
|
+
#end
|
12
|
+
|
13
|
+
begin
|
14
|
+
require 'jeweler'
|
15
|
+
|
16
|
+
Jeweler::Tasks.new do |gemspec|
|
17
|
+
gemspec.name = 'sinatra-authentication-gogolok'
|
18
|
+
gemspec.version = '0.0.5'
|
19
|
+
gemspec.description = "Simple authentication plugin for sinatra."
|
20
|
+
gemspec.summary = "Simple authentication plugin for sinatra."
|
21
|
+
gemspec.homepage = "http://github.com/gogolok/sinatra-authentication"
|
22
|
+
gemspec.author = "Max Justus Spransy"
|
23
|
+
gemspec.email = "maxjustus@gmail.com"
|
24
|
+
#gemspec.dependencies = ["sinatra", "dm-core", "dm-timestamps", "dm-validations", "rufus-tokyo"]
|
25
|
+
gemspec.add_dependency "sinatra"
|
26
|
+
gemspec.add_dependency "dm-core"
|
27
|
+
gemspec.add_dependency "dm-timestamps"
|
28
|
+
gemspec.add_dependency "dm-validations"
|
29
|
+
end
|
30
|
+
rescue LoadError
|
31
|
+
puts "Jeweler (or a dependency) not available. Install it first!"
|
32
|
+
end
|
33
|
+
|
34
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
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,49 @@
|
|
1
|
+
if Object.const_defined?("DataMapper")
|
2
|
+
#require 'dm-core'
|
3
|
+
require 'dm-timestamps'
|
4
|
+
require 'dm-validations'
|
5
|
+
require Pathname(__FILE__).dirname.expand_path + "datamapper_user.rb"
|
6
|
+
require Pathname(__FILE__).dirname.expand_path + "dm_adapter.rb"
|
7
|
+
elsif Object.const_defined?("Rufus")
|
8
|
+
require Pathname(__FILE__).dirname.expand_path + "rufus_tokyo_user.rb"
|
9
|
+
require Pathname(__FILE__).dirname.expand_path + "tc_adapter.rb"
|
10
|
+
end
|
11
|
+
|
12
|
+
class User
|
13
|
+
if Object.const_defined?("DataMapper")
|
14
|
+
include DmAdapter
|
15
|
+
elsif Object.const_defined?("Rufus")
|
16
|
+
include TcAdapter
|
17
|
+
else
|
18
|
+
throw "you need to require either 'dm-core' or 'rufus-tokyo' for sinatra-authentication to work"
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(interfacing_class_instance)
|
22
|
+
@instance = interfacing_class_instance
|
23
|
+
end
|
24
|
+
|
25
|
+
def id
|
26
|
+
@instance.id
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.authenticate(email, pass)
|
30
|
+
current_user = get(:email => email)
|
31
|
+
return nil if current_user.nil?
|
32
|
+
return current_user if User.encrypt(pass, current_user.salt) == current_user.hashed_password
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def self.encrypt(pass, salt)
|
39
|
+
Digest::SHA1.hexdigest(pass+salt)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.random_string(len)
|
43
|
+
#generate a random password consisting of strings and digits
|
44
|
+
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
|
45
|
+
newpass = ""
|
46
|
+
1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
|
47
|
+
return newpass
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class DmUser
|
2
|
+
include DataMapper::Resource
|
3
|
+
|
4
|
+
property :id, Serial
|
5
|
+
property :email, String, :key => true, :nullable => false, :length => (5..40), :unique => true, :format => :email_address
|
6
|
+
property :hashed_password, String
|
7
|
+
property :salt, String, :nullable => false
|
8
|
+
property :created_at, DateTime
|
9
|
+
property :permission_level, Integer, :default => 1
|
10
|
+
|
11
|
+
attr_accessor :password, :password_confirmation
|
12
|
+
#protected equievelant? :protected => true doesn't exist in dm 0.10.0
|
13
|
+
#protected :id, :salt
|
14
|
+
#doesn't behave correctly, I'm not even sure why I did this.
|
15
|
+
|
16
|
+
validates_present :password_confirmation, :unless => Proc.new { |t| t.hashed_password }
|
17
|
+
validates_present :password, :unless => Proc.new { |t| t.hashed_password }
|
18
|
+
validates_is_confirmed :password
|
19
|
+
|
20
|
+
def password=(pass)
|
21
|
+
@password = pass
|
22
|
+
self.salt = User.random_string(10) if !self.salt
|
23
|
+
self.hashed_password = User.encrypt(@password, self.salt)
|
24
|
+
end
|
25
|
+
|
26
|
+
def admin?
|
27
|
+
self.permission_level == -1 || self.id == 1
|
28
|
+
end
|
29
|
+
|
30
|
+
def site_admin?
|
31
|
+
self.id == 1
|
32
|
+
end
|
33
|
+
protected
|
34
|
+
|
35
|
+
def method_missing(m, *args)
|
36
|
+
return false
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module DmAdapter
|
2
|
+
def self.included(base)
|
3
|
+
base.extend ClassMethods
|
4
|
+
base.class_eval { include DmAdapter::InstanceMethods }
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def all
|
9
|
+
result = DmUser.all
|
10
|
+
result.collect {|instance| self.new instance}
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(hash)
|
14
|
+
if user = DmUser.first(hash)
|
15
|
+
self.new user
|
16
|
+
else
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def set(attributes)
|
22
|
+
user = DmUser.new attributes
|
23
|
+
user.save
|
24
|
+
user
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete(pk)
|
28
|
+
user = User.first(:id => pk)
|
29
|
+
user.destroy
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module InstanceMethods
|
34
|
+
def update(attributes)
|
35
|
+
@instance.update_attributes attributes
|
36
|
+
@instance.save
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_missing(meth, *args, &block)
|
40
|
+
#cool I just found out * on an array turns the array into a list of args for a function
|
41
|
+
@instance.send(meth, *args, &block)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
class TcUser
|
2
|
+
#include RufusOrm
|
3
|
+
|
4
|
+
#custom_attribute :salt
|
5
|
+
#custom_attribute :hashed_password
|
6
|
+
#custom_attribute :hashed_permission_level
|
7
|
+
#custom_attribute :created_at
|
8
|
+
#custom_attribute :created_at_i
|
9
|
+
|
10
|
+
#attribute method?
|
11
|
+
#if I'm gonna write all this, I might as well create a tinyyyy
|
12
|
+
#orm, that's more just like a way to define custom attributes for cabinets
|
13
|
+
#something worth noting though is that even datamapper defines custom
|
14
|
+
#attributes by allowing the developer to override setter methods.
|
15
|
+
#and it just calls all the setter methods defined in the model.
|
16
|
+
#the only trouble with this route is it assumes a predefined schema.
|
17
|
+
#and thus it knows what setter methods to call.
|
18
|
+
#I would write a class method that allows you to declare attributes like
|
19
|
+
#attribute :salt, with an optional block (which gets passed a hash of attributes)
|
20
|
+
#if a block isn't defined, it looks in the class for a salt=(attributes) function, calls it and marges the
|
21
|
+
#result into the hash going into the database, like 'attributes.merge{"salt" => result}'
|
22
|
+
#so my 'set' method or whatever I choose to call it, has to somehow look through each
|
23
|
+
#declared attribute, call the method associated with it, and merge the result into the hash going
|
24
|
+
#into the database.
|
25
|
+
#
|
26
|
+
#but what if I don't want an attribute passed in to be stored into the database? What if I just want to
|
27
|
+
#create a virtual attribute, for declaring other attributes?
|
28
|
+
#I might create a class variable that I store all the attributes in, and the I can get to it from any setter,
|
29
|
+
#and then after I've called all the setters, I store that class variable into the database.
|
30
|
+
#or, I do all of this on the instance level, and have a save method.
|
31
|
+
|
32
|
+
def initialize(attributes)
|
33
|
+
@attributes = attributes
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.query(&block)
|
37
|
+
connection = TcUserTable.new
|
38
|
+
result_set = connection.query(&block)
|
39
|
+
result_set.collect! { |result_hash| TcUser.new(result_hash) }
|
40
|
+
connection.close
|
41
|
+
result_set
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.get(key)
|
45
|
+
connection = TcUserTable.new
|
46
|
+
result = connection[key]
|
47
|
+
connection.close
|
48
|
+
if result
|
49
|
+
self.new(result.merge({:pk => key}))
|
50
|
+
else
|
51
|
+
false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.set(attributes)
|
56
|
+
#this way of validating is real crap, replace it with Validator maybe
|
57
|
+
#and maybe replace all this hash merging with setters for the various attributes that update @attributes, and then I can call save to store to the database
|
58
|
+
#or maybe just write a little method that makes hash merger look a little cleaner
|
59
|
+
pk = attributes.delete(:pk) if attributes[:pk]
|
60
|
+
|
61
|
+
email_regexp = /(\A(\s*)\Z)|(\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z)/i
|
62
|
+
if (attributes['password'] == attributes.delete('password_confirmation') && attributes['email'] =~ email_regexp)
|
63
|
+
password = attributes.delete('password')
|
64
|
+
attributes.merge!({'salt' => User.random_string(10)}) if !attributes['salt']
|
65
|
+
attributes.merge!('hashed_password' => User.encrypt(password, attributes['salt']))
|
66
|
+
permission_level = attributes['permission_level'] ? attributes['permission_level'] : '1'
|
67
|
+
attributes.merge!('permission_level' => permission_level)
|
68
|
+
attributes.merge!('created_at' => Time.now.to_s)
|
69
|
+
attributes.merge!('created_at_i' => Time.now.to_i.to_s)
|
70
|
+
|
71
|
+
connection = TcUserTable.new
|
72
|
+
pk ||= connection.genuid.to_s
|
73
|
+
#site admin if their first
|
74
|
+
attributes.merge!({'permission_level' => '-2'}) if pk == '1'
|
75
|
+
result = connection[pk] = attributes
|
76
|
+
#might not need this in newer version of rufus
|
77
|
+
result.merge!({:pk => pk})
|
78
|
+
connection.close
|
79
|
+
self.new(result)
|
80
|
+
else
|
81
|
+
false
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.delete(pk)
|
86
|
+
connection = TcUserTable.new
|
87
|
+
connection.delete(pk)
|
88
|
+
connection.close
|
89
|
+
end
|
90
|
+
|
91
|
+
def update(attributes)
|
92
|
+
new_attributes = @attributes.merge(attributes)
|
93
|
+
TcUser.set(new_attributes)
|
94
|
+
end
|
95
|
+
|
96
|
+
def [](key)
|
97
|
+
@attributes[key]
|
98
|
+
end
|
99
|
+
|
100
|
+
#saves to database and returns self
|
101
|
+
def []=(key, value)
|
102
|
+
@attributes[key] = value
|
103
|
+
#change so that it sets the attributes and then you call save to save to the database?
|
104
|
+
connection = TcUserTable.new
|
105
|
+
connection[@attributes[:pk]] = @attributes.merge!({key => value})
|
106
|
+
connection.close
|
107
|
+
self
|
108
|
+
end
|
109
|
+
|
110
|
+
def id
|
111
|
+
@attributes[:pk]
|
112
|
+
end
|
113
|
+
|
114
|
+
def admin?
|
115
|
+
#-2 is the site admin
|
116
|
+
@attributes['permission_level'] == '-1' || @attributes['permission_level'] == '-2'
|
117
|
+
end
|
118
|
+
|
119
|
+
def site_admin?
|
120
|
+
@attributes['permission_level'] == '-2'
|
121
|
+
end
|
122
|
+
|
123
|
+
#from hash extension for making hashes like javascript objects
|
124
|
+
def method_missing(meth,*args)
|
125
|
+
if /=$/=~(meth=meth.id2name) then
|
126
|
+
self[meth[0...-1]] = (args.length<2 ? args[0] : args)
|
127
|
+
elsif @attributes[meth]
|
128
|
+
@attributes[meth]
|
129
|
+
else
|
130
|
+
false
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class TcUserTable < Rufus::Tokyo::Table
|
136
|
+
@@path = false
|
137
|
+
def initialize
|
138
|
+
#make this path configurable somehow
|
139
|
+
raise "you need to define a path for the user cabinet to be stored at, like so: TcUserTable.cabinet_path = 'folder/where/you/wanna/store/your/database'" unless @@path
|
140
|
+
super(@@path + '/users.tct')
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.cabinet_path=(path)
|
144
|
+
@@path = path
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module TcAdapter
|
2
|
+
def self.included(base)
|
3
|
+
base.extend ClassMethods
|
4
|
+
base.class_eval {
|
5
|
+
include TcAdapter::InstanceMethods
|
6
|
+
alias :class_id :id
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
#TODO add pagination
|
12
|
+
def all
|
13
|
+
result = TcUser.query do |q|
|
14
|
+
q.order_by 'created_at_i', :numdesc
|
15
|
+
end
|
16
|
+
|
17
|
+
#these will be the same for all adapters, they should be defined in the user class, and these methods should have a different name?
|
18
|
+
result.collect {|instance| self.new instance }
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(hash)
|
22
|
+
#because with TcUser email and id are the same because the email is the id
|
23
|
+
if hash[:email]
|
24
|
+
result = TcUser.query do |q|
|
25
|
+
q.add 'email', :streq, hash[:email]
|
26
|
+
end[0]
|
27
|
+
#the zero is because this returns an array but get should return the first result
|
28
|
+
elsif hash[:id]
|
29
|
+
pk = hash[:id]
|
30
|
+
result = TcUser.get(pk)
|
31
|
+
end
|
32
|
+
|
33
|
+
if result
|
34
|
+
self.new result
|
35
|
+
else
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def set(attributes)
|
41
|
+
user = TcUser.query do |q|
|
42
|
+
q.add 'email', :streq, attributes['email']
|
43
|
+
end
|
44
|
+
|
45
|
+
if user == [] #no user
|
46
|
+
self.new TcUser.set(attributes)
|
47
|
+
else
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete(pk)
|
53
|
+
#true or false
|
54
|
+
!!TcUser.delete(pk)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module InstanceMethods
|
59
|
+
def update(attributes)
|
60
|
+
@instance.update attributes
|
61
|
+
end
|
62
|
+
|
63
|
+
def method_missing(meth, *args, &block)
|
64
|
+
#cool I just found out * on an array turn the array into a list of args for a function
|
65
|
+
@instance.send(meth, *args, &block)
|
66
|
+
end
|
67
|
+
|
68
|
+
#this was the only thing that didn't get passed on to method_missing because this is a method of object doh
|
69
|
+
def id
|
70
|
+
@instance.id
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'pathname'
|
3
|
+
require Pathname(__FILE__).dirname.expand_path + "models/abstract_user"
|
4
|
+
|
5
|
+
module SinatraAuthentication
|
6
|
+
VERSION = "0.0.3"
|
7
|
+
end
|
8
|
+
|
9
|
+
module Sinatra
|
10
|
+
module LilAuthentication
|
11
|
+
def self.registered(app)
|
12
|
+
#INVESTIGATE
|
13
|
+
#the possibility of sinatra having an array of view_paths to load from
|
14
|
+
#PROBLEM
|
15
|
+
#sinatra 9.1.1 doesn't have multiple view capability anywhere
|
16
|
+
#so to get around I have to do it totally manually by
|
17
|
+
#loading the view from this path into a string and rendering it
|
18
|
+
set :lil_authentication_view_path, Pathname(__FILE__).dirname.expand_path + "views/"
|
19
|
+
|
20
|
+
#TODO write captain sinatra developer man and inform him that the documentation
|
21
|
+
#concerning the writing of extensions is somewhat outdaded/incorrect.
|
22
|
+
#you do not need to to do self.get/self.post when writing an extension
|
23
|
+
#In fact, it doesn't work. You have to use the plain old sinatra DSL
|
24
|
+
|
25
|
+
get '/users' do
|
26
|
+
@users = User.all
|
27
|
+
if @users != []
|
28
|
+
haml get_view_as_string("index.haml"), :layout => use_layout?
|
29
|
+
else
|
30
|
+
redirect '/signup'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
get '/users/:id' do
|
35
|
+
login_required
|
36
|
+
|
37
|
+
#INVESTIGATE
|
38
|
+
#
|
39
|
+
#WHY THE HECK WON'T GET RETURN ANYTHING?
|
40
|
+
#if I user User.get(params[:id]) it returns nil for some inexplicable reason
|
41
|
+
@user = User.get(:id => params[:id])
|
42
|
+
haml get_view_as_string("show.haml"), :layout => use_layout?
|
43
|
+
end
|
44
|
+
|
45
|
+
#convenience for ajax but maybe entirely stupid and unnecesary
|
46
|
+
get '/logged_in' do
|
47
|
+
if session[:user]
|
48
|
+
"true"
|
49
|
+
else
|
50
|
+
"false"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
get '/login' do
|
55
|
+
haml get_view_as_string("login.haml"), :layout => use_layout?
|
56
|
+
end
|
57
|
+
|
58
|
+
post '/login' do
|
59
|
+
if user = User.authenticate(params[:email], params[:password])
|
60
|
+
session[:user] = user.id
|
61
|
+
redirect '/'
|
62
|
+
else
|
63
|
+
redirect '/login'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
get '/logout' do
|
68
|
+
session[:user] = nil
|
69
|
+
@message = "in case it weren't obvious, you've logged out"
|
70
|
+
redirect '/'
|
71
|
+
end
|
72
|
+
|
73
|
+
get '/signup' do
|
74
|
+
haml get_view_as_string("signup.haml"), :layout => use_layout?
|
75
|
+
end
|
76
|
+
|
77
|
+
post '/signup' do
|
78
|
+
@user = User.set(params[:user])
|
79
|
+
if @user
|
80
|
+
session[:user] = @user.id
|
81
|
+
redirect '/'
|
82
|
+
else
|
83
|
+
session[:flash] = "failure!"
|
84
|
+
redirect '/'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
get '/users/:id/edit' do
|
89
|
+
login_required
|
90
|
+
redirect "/users" unless current_user.admin? || current_user == params[:id]
|
91
|
+
|
92
|
+
@user = User.get(:id => params[:id])
|
93
|
+
haml get_view_as_string("edit.haml"), :layout => use_layout?
|
94
|
+
end
|
95
|
+
|
96
|
+
post '/users/:id/edit' do
|
97
|
+
login_required
|
98
|
+
redirect "/users" unless current_user.admin? || current_user == params[:id]
|
99
|
+
|
100
|
+
user = User.get(:id => params[:id])
|
101
|
+
user_attributes = params[:user]
|
102
|
+
if params[:user][:password] == ""
|
103
|
+
user_attributes.delete("password")
|
104
|
+
user_attributes.delete("password_confirmation")
|
105
|
+
end
|
106
|
+
|
107
|
+
if user.update(user_attributes)
|
108
|
+
redirect "/users/#{user.id}"
|
109
|
+
else
|
110
|
+
throw user.errors
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
get '/users/:id/delete' do
|
115
|
+
login_required
|
116
|
+
redirect "/users" unless current_user.admin? || current_user == params[:id]
|
117
|
+
|
118
|
+
if User.delete(params[:id])
|
119
|
+
session[:flash] = "way to go, you deleted a user"
|
120
|
+
else
|
121
|
+
session[:flash] = "deletion failed, for whatever reason"
|
122
|
+
end
|
123
|
+
redirect '/'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
module Helpers
|
129
|
+
def login_required
|
130
|
+
if session[:user]
|
131
|
+
return true
|
132
|
+
else
|
133
|
+
session[:return_to] = request.fullpath
|
134
|
+
redirect '/login'
|
135
|
+
return false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def current_user
|
140
|
+
if session[:user]
|
141
|
+
User.get(:id => session[:user])
|
142
|
+
else
|
143
|
+
GuestUser.new
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def logged_in?
|
148
|
+
!!session[:user]
|
149
|
+
end
|
150
|
+
|
151
|
+
def use_layout?
|
152
|
+
!request.xhr?
|
153
|
+
end
|
154
|
+
|
155
|
+
#BECAUSE sinatra 9.1.1 can't load views from different paths properly
|
156
|
+
def get_view_as_string(filename)
|
157
|
+
view = options.lil_authentication_view_path + filename
|
158
|
+
data = ""
|
159
|
+
f = File.open(view, "r")
|
160
|
+
f.each_line do |line|
|
161
|
+
data += line
|
162
|
+
end
|
163
|
+
return data
|
164
|
+
end
|
165
|
+
|
166
|
+
def render_login_logout(html_attributes = {:class => ""})
|
167
|
+
css_classes = html_attributes.delete(:class)
|
168
|
+
parameters = ''
|
169
|
+
html_attributes.each_pair do |attribute, value|
|
170
|
+
parameters += "#{attribute}=\"#{value}\" "
|
171
|
+
end
|
172
|
+
|
173
|
+
result = "<div id='sinatra-authentication-login-logout' >"
|
174
|
+
if logged_in?
|
175
|
+
logout_parameters = html_attributes
|
176
|
+
# a tad janky?
|
177
|
+
logout_parameters.delete(:rel)
|
178
|
+
result += "<a href='/users/#{current_user.id}/edit' class='#{css_classes} sinatra-authentication-edit' #{parameters}>edit account</a> "
|
179
|
+
result += "<a href='/logout' class='#{css_classes} sinatra-authentication-logout' #{logout_parameters}>logout</a>"
|
180
|
+
else
|
181
|
+
result += "<a href='/signup' class='#{css_classes} sinatra-authentication-signup' #{parameters}>signup</a> "
|
182
|
+
result += "<a href='/login' class='#{css_classes} sinatra-authentication-login' #{parameters}>login</a>"
|
183
|
+
end
|
184
|
+
|
185
|
+
result += "</div>"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
register LilAuthentication
|
190
|
+
end
|
191
|
+
|
192
|
+
class GuestUser
|
193
|
+
def guest?
|
194
|
+
true
|
195
|
+
end
|
196
|
+
|
197
|
+
def permission_level
|
198
|
+
0
|
199
|
+
end
|
200
|
+
|
201
|
+
# current_user.admin? returns false. current_user.has_a_baby? returns false.
|
202
|
+
# (which is a bit of an assumption I suppose)
|
203
|
+
def method_missing(m, *args)
|
204
|
+
return false
|
205
|
+
end
|
206
|
+
end
|
data/lib/views/edit.haml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#sinatra_authentication
|
2
|
+
%h1
|
3
|
+
Editing
|
4
|
+
= @user.email
|
5
|
+
%form{:action => "/users/#{@user.id}/edit", :method => "post"}
|
6
|
+
%input{ :id => "user_password", :name => "user[password]", :size => 30, :type => "password" }
|
7
|
+
new password
|
8
|
+
%br
|
9
|
+
%input{ :id => "user_password_confirmation", :name => "user[password_confirmation]", :size => 30, :type => "password" }
|
10
|
+
confirm
|
11
|
+
-# don't render permission field if admin and editing yourself so you don't shoot yourself in the foot
|
12
|
+
- if current_user.admin? && current_user.id != @user.id
|
13
|
+
%br
|
14
|
+
%select{ :id => "permission_level", :name => "user[permission_level]" }
|
15
|
+
%option{:value => -1, :selected => @user.admin?}
|
16
|
+
admin
|
17
|
+
%option{:value => 1, :selected => @user.permission_level == 1}
|
18
|
+
authenticated user
|
19
|
+
permission level
|
20
|
+
%br
|
21
|
+
%input{ :value => "update", :type => "submit" }
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#sinatra_authentication
|
2
|
+
%h1 Users
|
3
|
+
%table
|
4
|
+
%tr
|
5
|
+
%th email
|
6
|
+
- if current_user.admin?
|
7
|
+
%th permission level
|
8
|
+
- @users.each do |user|
|
9
|
+
%tr
|
10
|
+
%td= user.email
|
11
|
+
- if current_user.admin?
|
12
|
+
%td= user.permission_level
|
13
|
+
%td
|
14
|
+
%a{:href => "/users/#{user.id}"} show
|
15
|
+
- if current_user.admin?
|
16
|
+
%td
|
17
|
+
%a{:href => "/users/#{user.id}/edit"} edit
|
18
|
+
%td
|
19
|
+
-# this doesn't work for tk
|
20
|
+
- if !user.site_admin?
|
21
|
+
%a{:href => "/users/#{user.id}/delete", :onclick => "return confirm('you sure?')"} delete
|
22
|
+
- else
|
23
|
+
site admin
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#sinatra_authentication
|
2
|
+
%h1 Login
|
3
|
+
%form{:action => "/login", :method => "post"}
|
4
|
+
%input{:id => "user_email", :name => "email", :size => 30, :type => "text"}
|
5
|
+
email
|
6
|
+
%br
|
7
|
+
%input{:id => "user_password", :name => "password", :size => 30, :type => "password"}
|
8
|
+
password
|
9
|
+
%br
|
10
|
+
%input{:value => "login", :type => "submit"}
|
data/lib/views/show.haml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#sinatra_authentication
|
2
|
+
%h1 Signup
|
3
|
+
%form{:action => "/signup", :method => "post"}
|
4
|
+
%input{ :id => "user_email", :name => "user[email]", :size => 30, :type => "text" }
|
5
|
+
email
|
6
|
+
%br
|
7
|
+
%input{ :id => "user_password", :name => "user[password]", :size => 30, :type => "password" }
|
8
|
+
password
|
9
|
+
%br
|
10
|
+
%input{ :id => "user_password_confirmation", :name => "user[password_confirmation]", :size => 30, :type => "password" }
|
11
|
+
confirm
|
12
|
+
%br
|
13
|
+
%input{ :value => "sign up", :type => "submit" }
|
data/readme.markdown
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
### a little sinatra gem that implements user authentication, with support for both datamapper and rufus-tokyo
|
2
|
+
|
3
|
+
## INSTALLATION:
|
4
|
+
|
5
|
+
in your sinatra app simply require either "dm-core" or "rufus-tokyo" and then "sinatra-authentication" and turn on session storage
|
6
|
+
with a super secret key, like so:
|
7
|
+
|
8
|
+
require "dm-core"
|
9
|
+
require "sinatra-authentication"
|
10
|
+
|
11
|
+
use Rack::Session::Cookie, :secret => 'A1 sauce 1s so good you should use 1t on a11 yr st34ksssss'
|
12
|
+
|
13
|
+
If you're using rufus-tokyo, you also need to set the database path for Users. like so:
|
14
|
+
|
15
|
+
require "rufus_tokyo"
|
16
|
+
require "sinatra-authentication"
|
17
|
+
TcUserTable.cabinet_path = File.dirname(__FILE__) + 'folder/where/you/wanna/store/your/database'
|
18
|
+
|
19
|
+
use Rack::Session::Cookie, :secret => 'A1 sauce 1s so good you should use 1t on a11 yr st34ksssss'
|
20
|
+
|
21
|
+
## DEFAULT ROUTES:
|
22
|
+
|
23
|
+
* get '/login'
|
24
|
+
* get '/logout'
|
25
|
+
* get '/signup'
|
26
|
+
* get/post '/users'
|
27
|
+
* get '/users/:id'
|
28
|
+
* get/post '/users/:id/edit'
|
29
|
+
* get '/users/:id/delete'
|
30
|
+
|
31
|
+
If you fetch any of the user pages using ajax, they will automatically render without a layout
|
32
|
+
|
33
|
+
## HELPER METHODS:
|
34
|
+
|
35
|
+
This plugin provides the following helper methods for your sinatra app:
|
36
|
+
|
37
|
+
* login_required
|
38
|
+
> which you place at the beginning of any routes you want to be protected
|
39
|
+
* current_user
|
40
|
+
* logged_in?
|
41
|
+
* render_login_logout(html_attributes)
|
42
|
+
> Which renders login/logout and singup/edit account links.
|
43
|
+
If you pass a hash of html parameters to render_login_logout all the links will get set to them.
|
44
|
+
Which useful for if you're using some sort of lightbox
|
45
|
+
|
46
|
+
## SIMPLE PERMISSIONS:
|
47
|
+
|
48
|
+
By default the user class includes a method called admin? which simply checks
|
49
|
+
if user.permission_level == -1.
|
50
|
+
|
51
|
+
you can take advantage of this method in your views or controllers by calling
|
52
|
+
current_user.admin?
|
53
|
+
i.e.
|
54
|
+
|
55
|
+
- if current_user.admin?
|
56
|
+
%a{:href => "/adminey_link_route_thing"} do something adminey
|
57
|
+
|
58
|
+
(these view examples are in HAML, by the way)
|
59
|
+
|
60
|
+
You can also extend the user class with any convenience methods for determining permissions.
|
61
|
+
i.e.
|
62
|
+
|
63
|
+
#somewhere in the murky depths of your sinatra app
|
64
|
+
class User
|
65
|
+
def peasant?
|
66
|
+
self.permission_level == 0
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
then in your views you can do
|
71
|
+
|
72
|
+
- if current_user.peasant?
|
73
|
+
%h1 hello peasant!
|
74
|
+
%p Welcome to the caste system! It's very depressing.
|
75
|
+
|
76
|
+
if no one is logged in, current_user returns a GuestUser instance, which responds to current_user.guest?
|
77
|
+
with true, current_user.permission_level with 0 and any other method calls with false
|
78
|
+
|
79
|
+
This makes some view logic easier since you don't always have to check if the user is logged in,
|
80
|
+
although a logged_in? helper method is still provided
|
81
|
+
|
82
|
+
## RUFUS TOKYO
|
83
|
+
|
84
|
+
when using rufus-tokyo, current_user returns a hash, so to get the primary key of the current_user you would do current_user[:pk].
|
85
|
+
if you wanna set an attribute, you can do something like current_user["has_a_dog"] = true
|
86
|
+
and if you want to open a connection with the cabinet directly, you can do something like
|
87
|
+
|
88
|
+
user_connection = TcUser.new
|
89
|
+
users_with_gmail = user_connection.query do |q|
|
90
|
+
q.add 'email', :strinc, 'gmail'
|
91
|
+
end
|
92
|
+
user_connection.close
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{sinatra-authentication}
|
8
|
+
s.version = "0.0.5"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Max Justus Spransy"]
|
12
|
+
s.date = %q{2009-11-02}
|
13
|
+
s.description = %q{Simple authentication plugin for sinatra.}
|
14
|
+
s.email = %q{maxjustus@gmail.com}
|
15
|
+
s.files = [
|
16
|
+
".gitignore",
|
17
|
+
"History.txt",
|
18
|
+
"Manifest",
|
19
|
+
"Rakefile",
|
20
|
+
"TODO",
|
21
|
+
"lib/models/abstract_user.rb",
|
22
|
+
"lib/models/datamapper_user.rb",
|
23
|
+
"lib/models/dm_adapter.rb",
|
24
|
+
"lib/models/rufus_tokyo_user.rb",
|
25
|
+
"lib/models/tc_adapter.rb",
|
26
|
+
"lib/sinatra-authentication.rb",
|
27
|
+
"lib/views/edit.haml",
|
28
|
+
"lib/views/index.haml",
|
29
|
+
"lib/views/login.haml",
|
30
|
+
"lib/views/show.haml",
|
31
|
+
"lib/views/signup.haml",
|
32
|
+
"readme.markdown",
|
33
|
+
"sinatra-authentication.gemspec",
|
34
|
+
"test/datamapper_test.rb",
|
35
|
+
"test/lib/dm_app.rb",
|
36
|
+
"test/lib/helper.rb",
|
37
|
+
"test/lib/tc_app.rb",
|
38
|
+
"test/route_tests.rb",
|
39
|
+
"test/rufus_tokyo_test.rb"
|
40
|
+
]
|
41
|
+
s.homepage = %q{http://github.com/maxjustus/sinatra-authentication}
|
42
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
43
|
+
s.require_paths = ["lib"]
|
44
|
+
s.rubygems_version = %q{1.3.5}
|
45
|
+
s.summary = %q{Simple authentication plugin for sinatra.}
|
46
|
+
s.test_files = [
|
47
|
+
"test/lib/tc_app.rb",
|
48
|
+
"test/lib/helper.rb",
|
49
|
+
"test/lib/dm_app.rb",
|
50
|
+
"test/datamapper_test.rb",
|
51
|
+
"test/rufus_tokyo_test.rb",
|
52
|
+
"test/route_tests.rb"
|
53
|
+
]
|
54
|
+
|
55
|
+
if s.respond_to? :specification_version then
|
56
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
57
|
+
s.specification_version = 3
|
58
|
+
|
59
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
60
|
+
s.add_runtime_dependency(%q<sinatra>, [">= 0"])
|
61
|
+
s.add_runtime_dependency(%q<dm-core>, [">= 0"])
|
62
|
+
s.add_runtime_dependency(%q<dm-timestamgemspecs>, [">= 0"])
|
63
|
+
s.add_runtime_dependency(%q<dm-validations>, [">= 0"])
|
64
|
+
s.add_runtime_dependency(%q<rufus-tokyo>, [">= 0"])
|
65
|
+
else
|
66
|
+
s.add_dependency(%q<sinatra>, [">= 0"])
|
67
|
+
s.add_dependency(%q<dm-core>, [">= 0"])
|
68
|
+
s.add_dependency(%q<dm-timestamgemspecs>, [">= 0"])
|
69
|
+
s.add_dependency(%q<dm-validations>, [">= 0"])
|
70
|
+
s.add_dependency(%q<rufus-tokyo>, [">= 0"])
|
71
|
+
end
|
72
|
+
else
|
73
|
+
s.add_dependency(%q<sinatra>, [">= 0"])
|
74
|
+
s.add_dependency(%q<dm-core>, [">= 0"])
|
75
|
+
s.add_dependency(%q<dm-timestamgemspecs>, [">= 0"])
|
76
|
+
s.add_dependency(%q<dm-validations>, [">= 0"])
|
77
|
+
s.add_dependency(%q<rufus-tokyo>, [">= 0"])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
data/test/lib/dm_app.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra'
|
3
|
+
require 'haml'
|
4
|
+
require 'dm-core'
|
5
|
+
require File.join(File.dirname(__FILE__), '../../lib/sinatra-authentication')
|
6
|
+
|
7
|
+
DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/test.db")
|
8
|
+
DataMapper.auto_migrate!
|
9
|
+
|
10
|
+
use Rack::Session::Cookie, :secret => "heyhihello"
|
11
|
+
|
12
|
+
set :environment, 'development'
|
13
|
+
set :public, 'public'
|
14
|
+
set :views, 'views'
|
15
|
+
|
16
|
+
get '/' do
|
17
|
+
haml "hi", :layout => :layout
|
18
|
+
end
|
data/test/lib/helper.rb
ADDED
data/test/lib/tc_app.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra'
|
3
|
+
require 'haml'
|
4
|
+
require 'rufus/tokyo'
|
5
|
+
require File.join(File.dirname(__FILE__), '../../lib/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 "hi", :layout => :layout
|
16
|
+
end
|
data/test/route_tests.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
Test::Unit::TestCase.send :include, Rack::Test::Methods
|
2
|
+
|
3
|
+
class SinatraAuthDataMapperTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
post '/signup', TestHelper.gen_user
|
7
|
+
follow_redirect!
|
8
|
+
get '/logout'
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_should_login
|
12
|
+
post '/login', {'email' => TestHelper.gen_user['user[email]'], 'password' => TestHelper.gen_user['user[password]']}
|
13
|
+
follow_redirect!
|
14
|
+
|
15
|
+
assert_equal 'http://example.org/', last_request.url
|
16
|
+
#assert cookie_jar['user']
|
17
|
+
assert last_request.env['rack.session'][:user]
|
18
|
+
assert last_response.ok?
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_should_logout
|
22
|
+
post '/login', {'email' => TestHelper.gen_user['user[email]'], 'password' => TestHelper.gen_user['user[password]']}
|
23
|
+
get '/logout'
|
24
|
+
follow_redirect!
|
25
|
+
|
26
|
+
assert !last_request.env['rack.session'][:user]
|
27
|
+
assert_equal 'http://example.org/', last_request.url
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sinatra-authentication-gogolok
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Max Justus Spransy
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-02 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: sinatra
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: dm-core
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: dm-timestamps
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: dm-validations
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
description: Simple authentication plugin for sinatra.
|
56
|
+
email: maxjustus@gmail.com
|
57
|
+
executables: []
|
58
|
+
|
59
|
+
extensions: []
|
60
|
+
|
61
|
+
extra_rdoc_files: []
|
62
|
+
|
63
|
+
files:
|
64
|
+
- .gitignore
|
65
|
+
- History.txt
|
66
|
+
- Manifest
|
67
|
+
- Rakefile
|
68
|
+
- TODO
|
69
|
+
- lib/models/abstract_user.rb
|
70
|
+
- lib/models/datamapper_user.rb
|
71
|
+
- lib/models/dm_adapter.rb
|
72
|
+
- lib/models/rufus_tokyo_user.rb
|
73
|
+
- lib/models/tc_adapter.rb
|
74
|
+
- lib/sinatra-authentication.rb
|
75
|
+
- lib/views/edit.haml
|
76
|
+
- lib/views/index.haml
|
77
|
+
- lib/views/login.haml
|
78
|
+
- lib/views/show.haml
|
79
|
+
- lib/views/signup.haml
|
80
|
+
- readme.markdown
|
81
|
+
- sinatra-authentication.gemspec
|
82
|
+
- test/datamapper_test.rb
|
83
|
+
- test/lib/dm_app.rb
|
84
|
+
- test/lib/helper.rb
|
85
|
+
- test/lib/tc_app.rb
|
86
|
+
- test/route_tests.rb
|
87
|
+
- test/rufus_tokyo_test.rb
|
88
|
+
has_rdoc: true
|
89
|
+
homepage: http://github.com/gogolok/sinatra-authentication
|
90
|
+
licenses: []
|
91
|
+
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options:
|
94
|
+
- --charset=UTF-8
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: "0"
|
102
|
+
version:
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: "0"
|
108
|
+
version:
|
109
|
+
requirements: []
|
110
|
+
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 1.3.5
|
113
|
+
signing_key:
|
114
|
+
specification_version: 3
|
115
|
+
summary: Simple authentication plugin for sinatra.
|
116
|
+
test_files:
|
117
|
+
- test/datamapper_test.rb
|
118
|
+
- test/lib/dm_app.rb
|
119
|
+
- test/lib/helper.rb
|
120
|
+
- test/lib/tc_app.rb
|
121
|
+
- test/route_tests.rb
|
122
|
+
- test/rufus_tokyo_test.rb
|