entrance 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  class User < ActiveRecord::Base
2
2
  include Entrance::Model
3
-
4
- validate_entrance! # ensures everything is in order, and sets up password validations
3
+
4
+ provides_entrance
5
5
  end
@@ -28,7 +28,7 @@ class User
28
28
  key :reset_token
29
29
  key :reset_token_expires_at, Time
30
30
 
31
- validate_entrance! # ensures everything is in order, and sets up password validations
31
+ provides_entrance
32
32
 
33
33
  def active?
34
34
  state.to_sym == :active
@@ -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!'
@@ -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!
@@ -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.config.unique_key) : nil
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.config.unique_key] = session[:user_id]
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.config.remember_token_attr] = request.cookies[REMEMBER_ME_TOKEN]
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.config.remember_until_attr) > Time.now
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
@@ -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 validate_entrance!
19
- fields = if self.respond_to?(:columns) # ActiveRecord::Base
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
- %w(remember reset).each do |what|
35
- if field = Entrance.config.send("#{what}_token_attr")
36
- until_field = Entrance.config.send("#{what}_until_attr")
37
-
38
- unless fields.include?(field.to_sym)
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.config.username_attr] = username.to_s.downcase.strip
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.config.reset_token_attr] = token.to_s.strip
46
+ query[Entrance.fields.reset_token] = token.to_s.strip
79
47
  if u = where(query).first \
80
- and (!Doorman.config.reset_until_attr || u.send(Doorman.config.reset_until_attr) > Time.now)
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.config.reset_token_attr + '=', Entrance.generate_token)
91
- if Doorman.config.reset_until_attr
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.config.reset_until_attr, timestamp)
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.config.remember_token_attr, token) or return
108
- update_remember_token_expiration!(until_date) if Entrance.config.remember_until_attr
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.config.remember_until_attr, timestamp)
82
+ update_attribute(Entrance.fields.remember_until, timestamp)
115
83
  end
116
84
 
117
85
  def forget_me!
118
- update_attribute(Entrance.config.remember_token_attr, nil)
119
- update_attribute(Entrance.config.remember_until_attr, nil) if Entrance.config.remember_until_attr
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.config.salt_attr \
140
- and send(Entrance.config.salt_attr).nil?
141
- self.send(Entrance.config.salt_attr + '=', Entrance.generate_token)
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.config.password_attr + '=', encrypt_password(new_password))
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.config.password_attr)
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.config.salt_attr && send(Entrance.config.salt_attr)
126
+ Entrance.fields.salt && send(Entrance.fields.salt)
159
127
  end
160
128
 
161
129
  def password_required?
@@ -1,7 +1,7 @@
1
1
  module Entrance
2
2
  MAJOR = 0
3
- MINOR = 3
4
- PATCH = 4
3
+ MINOR = 4
4
+ PATCH = 0
5
5
 
6
6
  VERSION = [MAJOR, MINOR, PATCH].join('.')
7
7
  end
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
- include Entrance::Model # ensure after we declare the .where method
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.3.4
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