entrance 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/examples/rails-app/app/models/user.rb +2 -2
- data/examples/sinatra-app/app/models.rb +1 -1
- data/examples/sinatra-app/app/routes.rb +2 -0
- data/lib/entrance/config.rb +1 -16
- data/lib/entrance/controller.rb +4 -4
- data/lib/entrance/fields.rb +79 -0
- data/lib/entrance/model.rb +28 -60
- data/lib/entrance/version.rb +2 -2
- data/lib/entrance.rb +9 -4
- data/spec/fake_model.rb +10 -9
- metadata +2 -1
@@ -43,6 +43,8 @@ module Example
|
|
43
43
|
post '/login' do
|
44
44
|
if user = User.authenticate(params[:email], params[:password]) and user.active?
|
45
45
|
remember = ['on', '1'].include?(params[:remember_me])
|
46
|
+
|
47
|
+
puts user.inspect
|
46
48
|
login!(user, remember)
|
47
49
|
|
48
50
|
flash[:success] = 'Welcome back!'
|
data/lib/entrance/config.rb
CHANGED
@@ -20,18 +20,8 @@ module Entrance
|
|
20
20
|
@secret = nil
|
21
21
|
@stretches = 10
|
22
22
|
|
23
|
-
# fields
|
24
|
-
@salt_attr = nil
|
25
|
-
@unique_key = 'id'
|
26
|
-
@username_attr = 'email'
|
27
|
-
@password_attr = 'password_hash'
|
28
|
-
@remember_token_attr = 'remember_token'
|
29
|
-
@remember_until_attr = 'remember_token_expires_at'
|
30
|
-
@reset_token_attr = 'reset_token'
|
31
|
-
@reset_until_attr = 'reset_token_expires_at'
|
32
|
-
|
33
23
|
# access denied
|
34
|
-
@access_denied_redirect_to = '/'
|
24
|
+
@access_denied_redirect_to = '/login'
|
35
25
|
@access_denied_message_key = nil # e.g. 'messages.access_denied'
|
36
26
|
|
37
27
|
# reset password
|
@@ -45,11 +35,6 @@ module Entrance
|
|
45
35
|
@cookie_secure = true
|
46
36
|
@cookie_path = '/'
|
47
37
|
@cookie_httponly = false
|
48
|
-
|
49
|
-
# for omniauth support
|
50
|
-
@name_attr = 'name'
|
51
|
-
@auth_provider_attr = 'auth_provider'
|
52
|
-
@auth_uid_attr = 'auth_uid'
|
53
38
|
end
|
54
39
|
|
55
40
|
def validate!
|
data/lib/entrance/controller.rb
CHANGED
@@ -50,7 +50,7 @@ module Entrance
|
|
50
50
|
# new_user may be nil (when logging out) or an instance of the Entrance.model class
|
51
51
|
def current_user=(new_user)
|
52
52
|
raise "Invalid user: #{new_user}" unless new_user.nil? or new_user.is_a?(Entrance.model)
|
53
|
-
session[:user_id] = new_user ? new_user.send(Entrance.
|
53
|
+
session[:user_id] = new_user ? new_user.send(Entrance.fields.unique_key) : nil
|
54
54
|
@current_user = new_user # should be nil when logging out
|
55
55
|
end
|
56
56
|
|
@@ -78,7 +78,7 @@ module Entrance
|
|
78
78
|
|
79
79
|
def login_from_session
|
80
80
|
query = {}
|
81
|
-
query[Entrance.
|
81
|
+
query[Entrance.fields.unique_key] = session[:user_id]
|
82
82
|
self.current_user = Entrance.model.where(query).first if session[:user_id]
|
83
83
|
end
|
84
84
|
|
@@ -86,9 +86,9 @@ module Entrance
|
|
86
86
|
return unless Entrance.config.can?(:remember) && request.cookies[REMEMBER_ME_TOKEN]
|
87
87
|
|
88
88
|
query = {}
|
89
|
-
query[Entrance.
|
89
|
+
query[Entrance.fields.remember_token] = request.cookies[REMEMBER_ME_TOKEN]
|
90
90
|
if user = Entrance.model.where(query).first \
|
91
|
-
and user.send(Entrance.
|
91
|
+
and user.send(Entrance.fields.remember_until) > Time.now
|
92
92
|
self.current_user = user
|
93
93
|
# user.update_remember_token_expiration!
|
94
94
|
user
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Entrance
|
2
|
+
|
3
|
+
class Fields
|
4
|
+
|
5
|
+
attr_accessor *%w(
|
6
|
+
unique_key salt username password
|
7
|
+
remember_token remember_until reset_token reset_until
|
8
|
+
name auth_provider auth_uid
|
9
|
+
)
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@unique_key = 'id'
|
13
|
+
@salt = nil
|
14
|
+
@username = 'email'
|
15
|
+
@password = 'password_hash'
|
16
|
+
|
17
|
+
# remember and reset
|
18
|
+
@remember_token = 'remember_token'
|
19
|
+
@remember_until = 'remember_token_expires_at'
|
20
|
+
@reset_token = 'reset_token'
|
21
|
+
@reset_until = 'reset_token_expires_at'
|
22
|
+
|
23
|
+
# omniauth
|
24
|
+
@name = 'name'
|
25
|
+
@auth_provider = 'auth_provider'
|
26
|
+
@auth_uid = 'auth_uid'
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate!
|
30
|
+
raise "Invalid model: #{Entrance.config.model}!" unless Kernel.const_defined?(Entrance.config.model)
|
31
|
+
|
32
|
+
fields = get_model_fields
|
33
|
+
|
34
|
+
%w(username password).each do |attr|
|
35
|
+
field = send(attr)
|
36
|
+
unless fields.include?(field.to_sym)
|
37
|
+
raise "Couldn't find '#{field}' in the #{Entrance.model.name} model."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
%w(remember reset).each do |what|
|
42
|
+
if field = send("#{what}_token")
|
43
|
+
until_field = send("#{what}_until")
|
44
|
+
|
45
|
+
unless fields.include?(field.to_sym)
|
46
|
+
raise "No #{field} field found. \
|
47
|
+
Set the fields.#{what} option to nil to disable the #{what} option."
|
48
|
+
end
|
49
|
+
|
50
|
+
if until_field
|
51
|
+
unless fields.include?(until_field.to_sym)
|
52
|
+
raise "Couldn't find a #{until_field} field. Cannot continue."
|
53
|
+
end
|
54
|
+
else
|
55
|
+
puts "Disabling expiration timestamp for the #{what} option. This is a VERY bad idea."
|
56
|
+
end
|
57
|
+
|
58
|
+
Entrance.config.can?(what, true)
|
59
|
+
|
60
|
+
mod = what.to_sym == :remember ? Entrance::Model::RememberMethods : Entrance::Model::ResetMethods
|
61
|
+
Entrance.model.send(:include, mod)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_model_fields
|
67
|
+
model = Entrance.model
|
68
|
+
if model.respond_to?(:columns) # ActiveRecord::Base
|
69
|
+
model.columns.collect(&:name)
|
70
|
+
elsif model.respond_to?(:keys) # MongoMapper::Document
|
71
|
+
model.keys.keys
|
72
|
+
else # just get setters in the class
|
73
|
+
model.instance_methods(false).select { |m| m[/\=$/] }.map { |s| s.to_s.sub('=', '') }
|
74
|
+
end.map { |el| el.to_sym }
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
data/lib/entrance/model.rb
CHANGED
@@ -2,57 +2,25 @@ module Entrance
|
|
2
2
|
module Model
|
3
3
|
|
4
4
|
def self.included(base)
|
5
|
-
|
6
|
-
# if the target model class does not have a Model.where() method,
|
7
|
-
# then login_by_session wont work, nor the ClassMethods below.
|
8
|
-
# won't work so we cannot continue.
|
9
|
-
unless base.respond_to?(:where)
|
10
|
-
raise "#{base.name} does not have a .where() finder class method. Cannot continue."
|
11
|
-
end
|
12
|
-
|
13
5
|
base.extend(ClassMethods)
|
14
6
|
end
|
15
7
|
|
16
8
|
module ClassMethods
|
17
9
|
|
18
|
-
def
|
19
|
-
|
20
|
-
columns.collect(&:name)
|
21
|
-
elsif self.respond_to?(:keys) # MongoMapper::Document
|
22
|
-
keys.keys
|
23
|
-
else # just get setters in the class
|
24
|
-
instance_methods(false).select { |m| m[/\=$/] }.map { |s| s.to_s.sub('=', '') }
|
25
|
-
end.map { |el| el.to_sym }
|
26
|
-
|
27
|
-
%w(username_attr password_attr).each do |key|
|
28
|
-
field = Entrance.config.send(key)
|
29
|
-
unless fields.include?(field.to_sym)
|
30
|
-
raise "Couldn't find '#{field}' in #{self.name} model."
|
31
|
-
end
|
32
|
-
end
|
10
|
+
def provides_entrance(&block)
|
11
|
+
Entrance.config.model = self.name
|
33
12
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
raise "No #{Entrance.config.send("#{what}_token_attr")} field found. \
|
40
|
-
Set the config.#{what}_token_attr option to nil to disable the #{what} option."
|
41
|
-
end
|
42
|
-
|
43
|
-
if until_field
|
44
|
-
unless fields.include?(until_field.to_sym)
|
45
|
-
raise "Couldn't find a #{Entrance.config.send("#{what}_until_attr")} field. Cannot continue."
|
46
|
-
end
|
47
|
-
else
|
48
|
-
puts "Disabling expiration timestamp for the #{what} option. This is a VERY bad idea."
|
49
|
-
end
|
50
|
-
|
51
|
-
Entrance.config.can?(what, true)
|
52
|
-
self.send(:include, what.to_sym == :remember ? RememberMethods : ResetMethods)
|
53
|
-
end
|
13
|
+
# if the target model class does not have a Model.where() method,
|
14
|
+
# then login_by_session wont work, nor the ClassMethods below.
|
15
|
+
# won't work so we cannot continue.
|
16
|
+
unless self.respond_to?(:where)
|
17
|
+
raise "#{self.name} does not have a .where() finder class method. Cannot continue."
|
54
18
|
end
|
55
19
|
|
20
|
+
fields = Entrance.fields
|
21
|
+
yield fields if block_given?
|
22
|
+
fields.validate!
|
23
|
+
|
56
24
|
if self.respond_to?(:validates)
|
57
25
|
validates :password, :presence => true, :length => 6..32, :if => :password_required?
|
58
26
|
validates :password, :confirmation => true, :if => :password_required?
|
@@ -64,7 +32,7 @@ module Entrance
|
|
64
32
|
return if [username, password].any? { |v| v.nil? || v.strip == '' }
|
65
33
|
|
66
34
|
query = {}
|
67
|
-
query[Entrance.
|
35
|
+
query[Entrance.fields.username] = username.to_s.downcase.strip
|
68
36
|
if u = where(query).first
|
69
37
|
return u.authenticated?(password) ? u : nil
|
70
38
|
end
|
@@ -75,9 +43,9 @@ module Entrance
|
|
75
43
|
return if token.nil?
|
76
44
|
|
77
45
|
query = {}
|
78
|
-
query[Entrance.
|
46
|
+
query[Entrance.fields.reset_token] = token.to_s.strip
|
79
47
|
if u = where(query).first \
|
80
|
-
and (!
|
48
|
+
and (!Entrance.fields.reset_until || u.send(Entrance.fields.reset_until) > Time.now)
|
81
49
|
return u
|
82
50
|
end
|
83
51
|
end
|
@@ -87,10 +55,10 @@ module Entrance
|
|
87
55
|
module ResetMethods
|
88
56
|
|
89
57
|
def request_password_reset!
|
90
|
-
send(Entrance.
|
91
|
-
if
|
58
|
+
send(Entrance.fields.reset_token + '=', Entrance.generate_token)
|
59
|
+
if Entrance.fields.reset_until
|
92
60
|
timestamp = Time.now + Entrance.config.reset_password_window
|
93
|
-
update_attribute(Entrance.
|
61
|
+
update_attribute(Entrance.fields.reset_until, timestamp)
|
94
62
|
end
|
95
63
|
if save(:validate => false)
|
96
64
|
method = Entrance.config.reset_password_method
|
@@ -104,19 +72,19 @@ module Entrance
|
|
104
72
|
|
105
73
|
def remember_me!(until_date = nil)
|
106
74
|
token = Entrance.generate_token
|
107
|
-
update_attribute(Entrance.
|
108
|
-
update_remember_token_expiration!(until_date) if Entrance.
|
75
|
+
update_attribute(Entrance.fields.remember_token, token) or return
|
76
|
+
update_remember_token_expiration!(until_date) if Entrance.fields.remember_until
|
109
77
|
token
|
110
78
|
end
|
111
79
|
|
112
80
|
def update_remember_token_expiration!(until_date = nil)
|
113
81
|
timestamp = Time.now + (until_date || Entrance.config.remember_for).to_i
|
114
|
-
update_attribute(Entrance.
|
82
|
+
update_attribute(Entrance.fields.remember_until, timestamp)
|
115
83
|
end
|
116
84
|
|
117
85
|
def forget_me!
|
118
|
-
update_attribute(Entrance.
|
119
|
-
update_attribute(Entrance.
|
86
|
+
update_attribute(Entrance.fields.remember_token, nil)
|
87
|
+
update_attribute(Entrance.fields.remember_until, nil) if Entrance.fields.remember_until
|
120
88
|
end
|
121
89
|
|
122
90
|
end
|
@@ -136,18 +104,18 @@ module Entrance
|
|
136
104
|
@password_changed = true
|
137
105
|
|
138
106
|
# if we're using salt and it is empty, generate one
|
139
|
-
if Entrance.
|
140
|
-
and send(Entrance.
|
141
|
-
self.send(Entrance.
|
107
|
+
if Entrance.fields.salt \
|
108
|
+
and send(Entrance.fields.salt).nil?
|
109
|
+
self.send(Entrance.fields.salt + '=', Entrance.generate_token)
|
142
110
|
end
|
143
111
|
|
144
|
-
self.send(Entrance.
|
112
|
+
self.send(Entrance.fields.password + '=', encrypt_password(new_password))
|
145
113
|
end
|
146
114
|
|
147
115
|
private
|
148
116
|
|
149
117
|
def read_password
|
150
|
-
send(Entrance.
|
118
|
+
send(Entrance.fields.password)
|
151
119
|
end
|
152
120
|
|
153
121
|
def encrypt_password(string)
|
@@ -155,7 +123,7 @@ module Entrance
|
|
155
123
|
end
|
156
124
|
|
157
125
|
def get_salt
|
158
|
-
Entrance.
|
126
|
+
Entrance.fields.salt && send(Entrance.fields.salt)
|
159
127
|
end
|
160
128
|
|
161
129
|
def password_required?
|
data/lib/entrance/version.rb
CHANGED
data/lib/entrance.rb
CHANGED
@@ -2,6 +2,7 @@ require 'entrance/controller'
|
|
2
2
|
require 'entrance/model'
|
3
3
|
require 'entrance/ciphers'
|
4
4
|
require 'entrance/config'
|
5
|
+
require 'entrance/fields'
|
5
6
|
require 'digest/sha1'
|
6
7
|
|
7
8
|
module Entrance
|
@@ -10,15 +11,19 @@ module Entrance
|
|
10
11
|
@config ||= Config.new
|
11
12
|
end
|
12
13
|
|
14
|
+
def self.model
|
15
|
+
@model ||= Kernel.const_get(config.model)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.fields
|
19
|
+
@fields ||= Fields.new
|
20
|
+
end
|
21
|
+
|
13
22
|
def self.configure
|
14
23
|
yield config
|
15
24
|
config.validate!
|
16
25
|
end
|
17
26
|
|
18
|
-
def self.model
|
19
|
-
@model ||= Kernel.const_get(config.model)
|
20
|
-
end
|
21
|
-
|
22
27
|
def self.generate_token(length = 40)
|
23
28
|
str = Digest::SHA1.hexdigest([Time.now, rand].join)
|
24
29
|
str[0..(length-1)]
|
data/spec/fake_model.rb
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
require 'entrance'
|
2
2
|
|
3
3
|
Entrance.configure do |config|
|
4
|
-
config.model = 'FakeUser'
|
5
|
-
config.unique_key = 'email'
|
6
|
-
config.username_attr = 'email'
|
7
|
-
config.password_attr = 'password'
|
8
4
|
|
9
|
-
# disabling reset password and remember options
|
10
|
-
config.reset_token_attr = nil
|
11
|
-
config.remember_token_attr = nil
|
12
|
-
# config.cookie_secure = false
|
13
5
|
|
14
6
|
config.access_denied_redirect_to = '/login'
|
15
7
|
end
|
@@ -18,6 +10,7 @@ end
|
|
18
10
|
# admin user model
|
19
11
|
|
20
12
|
class FakeUser
|
13
|
+
include Entrance::Model
|
21
14
|
attr_accessor :email, :password #, :remember_token
|
22
15
|
|
23
16
|
USERS = {
|
@@ -47,6 +40,14 @@ class FakeUser
|
|
47
40
|
password == string
|
48
41
|
end
|
49
42
|
|
50
|
-
|
43
|
+
provides_entrance do |fields|
|
44
|
+
fields.unique_key = 'email'
|
45
|
+
fields.username = 'email'
|
46
|
+
fields.password = 'password'
|
47
|
+
|
48
|
+
# disabling reset password and remember options
|
49
|
+
fields.reset_token = nil
|
50
|
+
fields.remember_token = nil
|
51
|
+
end
|
51
52
|
|
52
53
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: entrance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -117,6 +117,7 @@ files:
|
|
117
117
|
- lib/entrance/ciphers.rb
|
118
118
|
- lib/entrance/config.rb
|
119
119
|
- lib/entrance/controller.rb
|
120
|
+
- lib/entrance/fields.rb
|
120
121
|
- lib/entrance/model.rb
|
121
122
|
- lib/entrance/version.rb
|
122
123
|
- spec/controller_spec.rb
|