entrance 0.3.4 → 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/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
|