sinatra-authentication 0.3.2 → 0.4.0
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/Rakefile +6 -1
- data/lib/models/abstract_user.rb +39 -1
- data/lib/models/datamapper_user.rb +2 -1
- data/lib/models/dm_adapter.rb +15 -4
- data/lib/models/mm_adapter.rb +21 -9
- data/lib/models/mongoid_adapter.rb +67 -0
- data/lib/models/mongoid_user.rb +41 -0
- data/lib/models/mongomapper_user.rb +4 -8
- data/lib/models/rufus_tokyo_user.rb +48 -19
- data/lib/models/sequel_adapter.rb +68 -0
- data/lib/models/sequel_user.rb +53 -0
- data/lib/models/tc_adapter.rb +20 -2
- data/lib/sinatra-authentication.rb +35 -23
- data/lib/sinatra-authentication/models.rb +5 -0
- data/lib/views/edit.haml +1 -1
- data/lib/views/login.haml +3 -3
- data/lib/views/signup.haml +4 -4
- data/readme.markdown +53 -3
- data/sinatra-authentication-0.3.2.gem +0 -0
- data/sinatra-authentication.gemspec +86 -60
- data/spec/run_all_specs.rb +8 -0
- data/spec/unit/dm_model_spec.rb +3 -0
- data/spec/unit/mm_model_spec.rb +3 -0
- data/spec/unit/mongoid_model_spec.rb +3 -0
- data/spec/unit/sequel_model_spec.rb +10 -0
- data/spec/unit/tc_model_spec.rb +3 -0
- data/spec/unit/user_specs.rb +119 -0
- data/test/lib/dm_app.rb +1 -0
- data/test/lib/dm_extend_app.rb +1 -0
- data/test/lib/extend_views/edit.haml +4 -0
- data/test/lib/extend_views/signup.haml +4 -4
- data/test/lib/helper.rb +4 -0
- data/test/lib/mm_app.rb +16 -15
- data/test/lib/mongoid_app.rb +29 -0
- data/test/lib/sequel_app.rb +22 -0
- data/test/lib/tc_app.rb +2 -0
- data/test/mongoid_test.rb +5 -0
- data/test/mongomapper_test.rb +36 -35
- data/test/sequel_test.rb +5 -0
- metadata +40 -24
- data/.gitignore +0 -4
data/Rakefile
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
|
+
#require 'spec/rake/spectask'
|
3
4
|
|
4
5
|
begin
|
5
6
|
require 'jeweler'
|
6
7
|
|
7
8
|
Jeweler::Tasks.new do |gemspec|
|
8
9
|
gemspec.name = 'sinatra-authentication'
|
9
|
-
gemspec.version = '0.
|
10
|
+
gemspec.version = '0.4.0'
|
10
11
|
gemspec.description = "Simple authentication plugin for sinatra."
|
11
12
|
gemspec.summary = "Simple authentication plugin for sinatra."
|
12
13
|
gemspec.homepage = "http://github.com/maxjustus/sinatra-authentication"
|
@@ -36,3 +37,7 @@ Rake::TestTask.new do |t|
|
|
36
37
|
t.verbose = true
|
37
38
|
end
|
38
39
|
|
40
|
+
#desc 'Run all specs'
|
41
|
+
#Spec::Rake::SpecTask.new('specs') do |t|
|
42
|
+
# t.spec_files = FileList['spec/**/*.rb']
|
43
|
+
#end
|
data/lib/models/abstract_user.rb
CHANGED
@@ -10,6 +10,12 @@ elsif Object.const_defined?("Rufus") && Rufus.const_defined?("Tokyo")
|
|
10
10
|
elsif Object.const_defined?("MongoMapper")
|
11
11
|
require Pathname(__FILE__).dirname.expand_path + "mongomapper_user.rb"
|
12
12
|
require Pathname(__FILE__).dirname.expand_path + "mm_adapter.rb"
|
13
|
+
elsif Object.const_defined?("Sequel")
|
14
|
+
require Pathname(__FILE__).dirname.expand_path + "sequel_user.rb"
|
15
|
+
require Pathname(__FILE__).dirname.expand_path + "sequel_adapter.rb"
|
16
|
+
elsif Object.const_defined?("Mongoid")
|
17
|
+
require Pathname(__FILE__).dirname.expand_path + "mongoid_user.rb"
|
18
|
+
require Pathname(__FILE__).dirname.expand_path + "mongoid_adapter.rb"
|
13
19
|
end
|
14
20
|
|
15
21
|
class User
|
@@ -19,8 +25,12 @@ class User
|
|
19
25
|
include TcAdapter
|
20
26
|
elsif Object.const_defined?("MongoMapper")
|
21
27
|
include MmAdapter
|
28
|
+
elsif Object.const_defined?("Sequel")
|
29
|
+
include SequelAdapter
|
30
|
+
elsif Object.const_defined?("Mongoid")
|
31
|
+
include MongoidAdapter
|
22
32
|
else
|
23
|
-
throw "you need to require either 'dm-core', 'mongo_mapper', or 'rufus-tokyo' for sinatra-authentication to work"
|
33
|
+
throw "you need to require either 'dm-core', 'mongo_mapper', 'sequel', 'mongoid', or 'rufus-tokyo' for sinatra-authentication to work"
|
24
34
|
end
|
25
35
|
|
26
36
|
def initialize(interfacing_class_instance)
|
@@ -38,6 +48,10 @@ class User
|
|
38
48
|
nil
|
39
49
|
end
|
40
50
|
|
51
|
+
def db_instance
|
52
|
+
@instance
|
53
|
+
end
|
54
|
+
|
41
55
|
protected
|
42
56
|
|
43
57
|
def self.encrypt(pass, salt)
|
@@ -51,4 +65,28 @@ class User
|
|
51
65
|
1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
|
52
66
|
return newpass
|
53
67
|
end
|
68
|
+
|
69
|
+
#def self.page_limit
|
70
|
+
# 20
|
71
|
+
#end
|
72
|
+
|
73
|
+
#def self.page_offset(page = 0)
|
74
|
+
# page.to_i * self.page_limit
|
75
|
+
#end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Hash
|
79
|
+
def stringify
|
80
|
+
inject({}) do |options, (key, value)|
|
81
|
+
options[key.to_s] = value.to_s
|
82
|
+
options
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def stringify!
|
87
|
+
each do |key, value|
|
88
|
+
delete(key)
|
89
|
+
store(key.to_s, value.to_s)
|
90
|
+
end
|
91
|
+
end
|
54
92
|
end
|
@@ -5,7 +5,8 @@ class DmUser
|
|
5
5
|
property :email, String, :length => (5..40), :unique => true, :format => :email_address
|
6
6
|
property :hashed_password, String
|
7
7
|
property :salt, String
|
8
|
-
|
8
|
+
#Was DateTime should be DateTime?
|
9
|
+
property :created_at, Time
|
9
10
|
property :permission_level, Integer, :default => 1
|
10
11
|
if Sinatra.const_defined?('FacebookObject')
|
11
12
|
property :fb_uid, String
|
data/lib/models/dm_adapter.rb
CHANGED
@@ -6,8 +6,8 @@ module DmAdapter
|
|
6
6
|
|
7
7
|
module ClassMethods
|
8
8
|
#pass all args to this
|
9
|
-
def all
|
10
|
-
result = DmUser.all(
|
9
|
+
def all
|
10
|
+
result = DmUser.all(:order => [:created_at.desc])
|
11
11
|
result.collect {|instance| self.new instance}
|
12
12
|
end
|
13
13
|
|
@@ -22,13 +22,13 @@ module DmAdapter
|
|
22
22
|
def set(attributes)
|
23
23
|
user = DmUser.new attributes
|
24
24
|
user.save
|
25
|
-
user
|
25
|
+
self.new user
|
26
26
|
end
|
27
27
|
|
28
28
|
def set!(attributes)
|
29
29
|
user = DmUser.new attributes
|
30
30
|
user.save!
|
31
|
-
user
|
31
|
+
self.new user
|
32
32
|
end
|
33
33
|
|
34
34
|
def delete(pk)
|
@@ -38,8 +38,19 @@ module DmAdapter
|
|
38
38
|
end
|
39
39
|
|
40
40
|
module InstanceMethods
|
41
|
+
def valid
|
42
|
+
@instance.valid?
|
43
|
+
end
|
44
|
+
|
45
|
+
def errors
|
46
|
+
@instance.errors.collect do |k,v|
|
47
|
+
"#{k} #{v}"
|
48
|
+
end.join(', ')
|
49
|
+
end
|
50
|
+
|
41
51
|
def update(attributes)
|
42
52
|
@instance.update attributes
|
53
|
+
#self
|
43
54
|
end
|
44
55
|
|
45
56
|
def method_missing(meth, *args, &block)
|
data/lib/models/mm_adapter.rb
CHANGED
@@ -6,7 +6,7 @@ module MmAdapter
|
|
6
6
|
|
7
7
|
module ClassMethods
|
8
8
|
def all
|
9
|
-
result = MmUser.all
|
9
|
+
result = MmUser.all(:order => 'created_at desc')
|
10
10
|
result.collect {|instance| self.new instance}
|
11
11
|
end
|
12
12
|
|
@@ -19,32 +19,44 @@ module MmAdapter
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def set(attributes)
|
22
|
-
puts attributes.inspect
|
22
|
+
#puts attributes.inspect
|
23
23
|
user = MmUser.new attributes
|
24
|
-
|
25
|
-
|
26
|
-
user.save
|
27
|
-
user
|
24
|
+
user.id = nil unless user.save
|
25
|
+
self.new user
|
28
26
|
end
|
29
27
|
|
30
28
|
def set!(attributes)
|
31
29
|
user = MmUser.new attributes
|
32
|
-
user.save
|
33
|
-
user
|
30
|
+
user.save(:validate => false)
|
31
|
+
self.new user
|
34
32
|
end
|
35
33
|
|
36
34
|
def delete(pk)
|
37
|
-
user =
|
35
|
+
user = MmUser.first(:id => pk)
|
36
|
+
#returns nil on success. Is this correct? Will it return something else on failure?
|
38
37
|
user.destroy
|
38
|
+
user.destroyed?
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
module InstanceMethods
|
43
|
+
def valid
|
44
|
+
@instance.valid?
|
45
|
+
end
|
46
|
+
|
43
47
|
def update(attributes)
|
44
48
|
@instance.update_attributes attributes
|
45
49
|
@instance.save
|
46
50
|
end
|
47
51
|
|
52
|
+
def saved
|
53
|
+
@instance.valid?
|
54
|
+
end
|
55
|
+
|
56
|
+
def errors
|
57
|
+
@instance.errors.full_messages.join(', ')
|
58
|
+
end
|
59
|
+
|
48
60
|
def method_missing(meth, *args, &block)
|
49
61
|
#cool I just found out * on an array turns the array into a list of args for a function
|
50
62
|
@instance.send(meth, *args, &block)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module MongoidAdapter
|
2
|
+
def self.included(base)
|
3
|
+
base.extend ClassMethods
|
4
|
+
base.class_eval { include MongoidAdapter::InstanceMethods }
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def all
|
9
|
+
result = MongoidUser.criteria.order_by([[:created_at, :desc]])
|
10
|
+
result.collect {|instance| self.new instance }
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(hash)
|
14
|
+
if user = MongoidUser.first(:conditions => hash)
|
15
|
+
self.new user
|
16
|
+
else
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def set(attributes)
|
22
|
+
#puts attributes.inspect
|
23
|
+
user = MongoidUser.new attributes
|
24
|
+
#puts user.inspect
|
25
|
+
#puts user.to_json
|
26
|
+
user.save
|
27
|
+
self.new user
|
28
|
+
end
|
29
|
+
|
30
|
+
def set!(attributes)
|
31
|
+
user = MongoidUser.new attributes
|
32
|
+
user.save(:validate => false)
|
33
|
+
self.new user
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete(pk)
|
37
|
+
user = MongoidUser.find(pk)
|
38
|
+
#returns nil on success. Is this correct? Will it return something else on failure?
|
39
|
+
user.destroy
|
40
|
+
user.destroyed?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module InstanceMethods
|
45
|
+
def valid
|
46
|
+
@instance.valid?
|
47
|
+
end
|
48
|
+
|
49
|
+
def update(attributes)
|
50
|
+
@instance.update_attributes(attributes)
|
51
|
+
@instance.save
|
52
|
+
end
|
53
|
+
|
54
|
+
def saved
|
55
|
+
@instance.valid?
|
56
|
+
end
|
57
|
+
|
58
|
+
def errors
|
59
|
+
@instance.errors.full_messages.join(', ')
|
60
|
+
end
|
61
|
+
|
62
|
+
def method_missing(meth, *args, &block)
|
63
|
+
#cool I just found out * on an array turns the array into a list of args for a function
|
64
|
+
@instance.send(meth, *args, &block)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class MongoidUser
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Timestamps
|
4
|
+
field :email
|
5
|
+
field :hashed_password
|
6
|
+
field :salt
|
7
|
+
field :permission_level, :type => Integer, :default => 1
|
8
|
+
if Sinatra.const_defined?('FacebookObject')
|
9
|
+
field :fb_uid
|
10
|
+
end
|
11
|
+
|
12
|
+
# Validations
|
13
|
+
validates_uniqueness_of :email
|
14
|
+
validates_format_of :email, :with => /(\A(\s*)\Z)|(\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z)/i
|
15
|
+
validates_presence_of :password
|
16
|
+
validates_confirmation_of :password
|
17
|
+
|
18
|
+
#attr_protected :_id, :salt
|
19
|
+
|
20
|
+
attr_accessor :password, :password_confirmation
|
21
|
+
|
22
|
+
def password=(pass)
|
23
|
+
@password = pass
|
24
|
+
self.salt = User.random_string(10) if !self.salt
|
25
|
+
self.hashed_password = User.encrypt(@password, self.salt)
|
26
|
+
end
|
27
|
+
|
28
|
+
def admin?
|
29
|
+
self.permission_level == -1 || self.id == 1
|
30
|
+
end
|
31
|
+
|
32
|
+
def site_admin?
|
33
|
+
self.id == 1
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def method_missing(m, *args)
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
class MmUser
|
2
2
|
include MongoMapper::Document
|
3
3
|
|
4
|
-
|
4
|
+
email_regexp = /(\A(\s*)\Z)|(\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z)/i
|
5
|
+
key :email, String, :unique => true, :format => email_regexp
|
5
6
|
key :hashed_password, String
|
6
7
|
key :salt, String
|
7
8
|
key :permission_level, Integer, :default => 1
|
@@ -12,13 +13,8 @@ class MmUser
|
|
12
13
|
timestamps!
|
13
14
|
|
14
15
|
attr_accessor :password, :password_confirmation
|
15
|
-
|
16
|
-
|
17
|
-
#doesn't behave correctly, I'm not even sure why I did this.
|
18
|
-
|
19
|
-
#validates_presence_of :password_confirmation, :unless => Proc.new { |t| t.hashed_password }
|
20
|
-
#validates_presence_of :password, :unless => Proc.new { |t| t.hashed_password }
|
21
|
-
#validates_is_confirmed :password
|
16
|
+
validates_presence_of :password, :allow_blank => true
|
17
|
+
validates_confirmation_of :password
|
22
18
|
|
23
19
|
def password=(pass)
|
24
20
|
@password = pass
|
@@ -1,4 +1,5 @@
|
|
1
1
|
class TcUser
|
2
|
+
attr_accessor :errors
|
2
3
|
#include RufusOrm
|
3
4
|
|
4
5
|
#custom_attribute :salt
|
@@ -29,8 +30,13 @@ class TcUser
|
|
29
30
|
#and then after I've called all the setters, I store that class variable into the database.
|
30
31
|
#or, I do all of this on the instance level, and have a save method.
|
31
32
|
|
32
|
-
def initialize(attributes)
|
33
|
+
def initialize(attributes, errors = [])
|
33
34
|
@attributes = attributes
|
35
|
+
if @attributes['created_at']
|
36
|
+
@attributes['created_at'] = Time.parse(@attributes['created_at'])
|
37
|
+
end
|
38
|
+
|
39
|
+
@errors = errors
|
34
40
|
end
|
35
41
|
|
36
42
|
def self.query(&block)
|
@@ -58,26 +64,46 @@ class TcUser
|
|
58
64
|
#or maybe just write a little method that makes hash merger look a little cleaner
|
59
65
|
pk = attributes.delete(:pk) if attributes[:pk]
|
60
66
|
|
67
|
+
errors = []
|
68
|
+
|
61
69
|
email_regexp = /(\A(\s*)\Z)|(\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z)/i
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
70
|
+
attributes = attributes.stringify
|
71
|
+
|
72
|
+
unless attributes['email'] =~ email_regexp
|
73
|
+
errors << 'Email is invalid'
|
74
|
+
end
|
75
|
+
|
76
|
+
if attributes['password'] != attributes.delete('password_confirmation') && attributes['password'] != nil
|
77
|
+
errors << "Passwords don't match"
|
78
|
+
end
|
79
|
+
|
80
|
+
if attributes['password'] != nil && attributes['password'].length == 0
|
81
|
+
errors << "You need to provide a password"
|
82
|
+
end
|
83
|
+
|
84
|
+
if errors.length == 0
|
85
|
+
password = attributes.delete('password')
|
86
|
+
if !attributes['salt']
|
87
|
+
salt = User.random_string(10)
|
88
|
+
attributes.merge!({'salt' => salt})
|
89
|
+
attributes.merge!('hashed_password' => User.encrypt(password, salt))
|
90
|
+
end
|
91
|
+
permission_level = attributes['permission_level'] ? attributes['permission_level'] : '1'
|
92
|
+
attributes.merge!('permission_level' => permission_level)
|
93
|
+
if attributes['created_at']
|
94
|
+
attributes.merge!('created_at_i' => Time.parse(attributes['created_at']).to_i)
|
95
|
+
else
|
96
|
+
attributes.merge!('created_at' => Time.now.to_s)
|
97
|
+
attributes.merge!('created_at_i' => Time.now.to_i.to_s)
|
73
98
|
end
|
74
99
|
|
75
100
|
existing_user = TcUser.query do |q|
|
76
101
|
q.add 'email', :streq, attributes['email']
|
77
102
|
end[0]
|
78
103
|
|
79
|
-
if existing_user && existing_user[
|
80
|
-
|
104
|
+
if existing_user && existing_user[:pk] != pk
|
105
|
+
errors << "Email is already taken"
|
106
|
+
return self.new(attributes, errors)
|
81
107
|
else
|
82
108
|
connection = TcUserTable.new
|
83
109
|
pk ||= connection.genuid.to_s
|
@@ -87,10 +113,10 @@ class TcUser
|
|
87
113
|
#might not need this in newer version of rufus
|
88
114
|
result.merge!({:pk => pk})
|
89
115
|
connection.close
|
90
|
-
self.new(result)
|
116
|
+
self.new(result, errors)
|
91
117
|
end
|
92
118
|
else
|
93
|
-
|
119
|
+
self.new(attributes, errors)
|
94
120
|
end
|
95
121
|
end
|
96
122
|
|
@@ -110,8 +136,11 @@ class TcUser
|
|
110
136
|
end
|
111
137
|
|
112
138
|
def update(attributes)
|
139
|
+
self.errors = []
|
113
140
|
new_attributes = @attributes.merge(attributes)
|
114
|
-
TcUser.set(new_attributes)
|
141
|
+
updated_user = TcUser.set(new_attributes)
|
142
|
+
self.errors = updated_user.errors
|
143
|
+
updated_user.errors.length < 1
|
115
144
|
end
|
116
145
|
|
117
146
|
def [](key)
|
@@ -133,11 +162,11 @@ class TcUser
|
|
133
162
|
end
|
134
163
|
|
135
164
|
def admin?
|
136
|
-
|
137
|
-
@attributes['permission_level'] == '-1' || @attributes['permission_level'] == '-2'
|
165
|
+
@attributes['permission_level'] == '-1' || site_admin?
|
138
166
|
end
|
139
167
|
|
140
168
|
def site_admin?
|
169
|
+
#-2 is the site admin
|
141
170
|
@attributes['permission_level'] == '-2'
|
142
171
|
end
|
143
172
|
|