minimalist_authentication 2.0.0 → 2.1.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.
- checksums.yaml +4 -4
- data/README.md +44 -4
- data/app/controllers/email_verifications_controller.rb +16 -0
- data/app/controllers/emails_controller.rb +22 -0
- data/app/controllers/password_resets_controller.rb +30 -0
- data/app/controllers/passwords_controller.rb +34 -0
- data/app/mailers/application_mailer.rb +5 -0
- data/app/mailers/minimalist_authentication_mailer.rb +22 -0
- data/app/views/email_verifications/new.html.erb +14 -0
- data/app/views/email_verifications/show.html.erb +10 -0
- data/app/views/emails/edit.html.erb +12 -0
- data/app/views/layouts/mailer.html.erb +13 -0
- data/app/views/layouts/mailer.text.erb +1 -0
- data/app/views/minimalist_authentication_mailer/update_password.html.erb +3 -0
- data/app/views/minimalist_authentication_mailer/update_password.text.erb +3 -0
- data/app/views/minimalist_authentication_mailer/verify_email.html.erb +5 -0
- data/app/views/minimalist_authentication_mailer/verify_email.text.erb +5 -0
- data/app/views/password_resets/new.html.erb +13 -0
- data/app/views/passwords/edit.html.erb +17 -0
- data/app/views/sessions/_form.html.erb +9 -3
- data/app/views/sessions/new.html.erb +2 -0
- data/config/locales/minimalist_authentication.en.yml +7 -0
- data/config/routes.rb +8 -0
- data/lib/minimalist_authentication.rb +2 -0
- data/lib/minimalist_authentication/configuration.rb +32 -0
- data/lib/minimalist_authentication/email_verification.rb +41 -0
- data/lib/minimalist_authentication/sessions.rb +24 -4
- data/lib/minimalist_authentication/user.rb +17 -11
- data/lib/minimalist_authentication/verifiable_token.rb +51 -0
- data/lib/minimalist_authentication/version.rb +1 -1
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6646211204dbc15edbbe5a48d00546cdb826acde
|
4
|
+
data.tar.gz: 00dfd3515eb12f919abb0bff9da8e76823235065
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06de541cfc8129ab8fc70e39b5a4d29cd565f4dfdd26a38225d40a7dc0d18bed65f0ef3b1fb6c7530af964ebb7e7393916a9c4247c4212f0e5f995c1471f6b8c
|
7
|
+
data.tar.gz: d21ffa2de1ff35cbea0d03cbacf59ad5b0e6163c802065c474d4d4b830d3d015c76f12f5d295a86d5d3603c44e7a63b47010cdcdc6144ce032a91a26f2753514
|
data/README.md
CHANGED
@@ -65,10 +65,15 @@ end
|
|
65
65
|
Customize the configuration with an initializer. Create a **minimalist_authentication.rb** file in /Users/baldwina/git/brightways/config/initializers.
|
66
66
|
```ruby
|
67
67
|
MinimalistAuthentication.configure do |configuration|
|
68
|
-
configuration.user_model_name
|
69
|
-
configuration.session_key
|
70
|
-
validate_email
|
71
|
-
validate_email_presence
|
68
|
+
configuration.user_model_name = 'CustomModelName' # default is '::User'
|
69
|
+
configuration.session_key = :custom_session_key # default is :user_id
|
70
|
+
configuration.validate_email = true # default is true
|
71
|
+
configuration.validate_email_presence = true # default is true
|
72
|
+
configuration.request_email = true # default is true
|
73
|
+
configuration.verify_email = true # default is true
|
74
|
+
configuration.login_redirect_path = :custom_path # default is :root_path
|
75
|
+
configuration.logout_redirect_path = :custom_path # default is :new_session_path
|
76
|
+
configuration.email_prefix = '[Custom Prefix]' # default is application name
|
72
77
|
end
|
73
78
|
```
|
74
79
|
|
@@ -83,6 +88,41 @@ example_user:
|
|
83
88
|
```
|
84
89
|
|
85
90
|
|
91
|
+
## Verification Tokens
|
92
|
+
Verification token support is provided by the **MinimalistAuthentication::VerifiableToken**
|
93
|
+
module. Include the module in your user class and add the verification token columns
|
94
|
+
to the database.
|
95
|
+
|
96
|
+
Include MinimalistAuthentication::VerifiableToken in your user model (app/models/user.rb)
|
97
|
+
```ruby
|
98
|
+
class User < ApplicationRecord
|
99
|
+
include MinimalistAuthentication::User
|
100
|
+
include MinimalistAuthentication::VerifiableToken
|
101
|
+
end
|
102
|
+
```
|
103
|
+
|
104
|
+
Add the **verification_token** and **verification_token_generated_at** columns:
|
105
|
+
Create a user model with **email** for an identifier:
|
106
|
+
```bash
|
107
|
+
bin/rails generate migration AddVerificationTokenToUsers verification_token:string:uniq verification_token_generated_at:datetime
|
108
|
+
```
|
109
|
+
|
110
|
+
### Email Verification
|
111
|
+
Include MinimalistAuthentication::EmailVerification in your user model (app/models/user.rb)
|
112
|
+
```ruby
|
113
|
+
class User < ApplicationRecord
|
114
|
+
include MinimalistAuthentication::User
|
115
|
+
include MinimalistAuthentication::VerifiableToken
|
116
|
+
include MinimalistAuthentication::EmailVerification
|
117
|
+
end
|
118
|
+
```
|
119
|
+
|
120
|
+
Add the **email_verified_at** column to your user model:
|
121
|
+
```bash
|
122
|
+
bin/rails generate migration AddVerificationTokenToUsers verification_token:string:uniq verification_token_generated_at:datetime
|
123
|
+
```
|
124
|
+
|
125
|
+
|
86
126
|
## Conversions
|
87
127
|
Pre 2.0 versions of MinimalistAuthentication supported multiple hash algorithms
|
88
128
|
and stored the hashed password and salt as separate fields in the database
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class EmailVerificationsController < ApplicationController
|
2
|
+
def new
|
3
|
+
# verify email for current_user
|
4
|
+
end
|
5
|
+
|
6
|
+
def create
|
7
|
+
current_user.regenerate_verification_token
|
8
|
+
MinimalistAuthenticationMailer.verify_email(current_user).deliver_now
|
9
|
+
|
10
|
+
redirect_to dashboard_path, notice: "Verification email sent to #{current_user.email}, follow the instructions to complete verification. Thank you!"
|
11
|
+
end
|
12
|
+
|
13
|
+
def show
|
14
|
+
current_user.verify_email(params[:token])
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class EmailsController < ApplicationController
|
2
|
+
def edit
|
3
|
+
end
|
4
|
+
|
5
|
+
def update
|
6
|
+
if current_user.update_attributes(user_params)
|
7
|
+
redirect_to update_redirect_path, notice: 'Email successfully updated'
|
8
|
+
else
|
9
|
+
render :edit
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def user_params
|
16
|
+
params.require(:user).permit(:email)
|
17
|
+
end
|
18
|
+
|
19
|
+
def update_redirect_path
|
20
|
+
current_user.needs_email_verification? ? new_email_verification_path : dashboard_path
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class PasswordResetsController < ApplicationController
|
2
|
+
skip_before_action :authorization_required
|
3
|
+
|
4
|
+
layout 'sessions'
|
5
|
+
|
6
|
+
# Form for user to request a password reset
|
7
|
+
def new
|
8
|
+
@user = MinimalistAuthentication.configuration.user_model.new
|
9
|
+
end
|
10
|
+
|
11
|
+
# Send a password update link to users with a verified email
|
12
|
+
def create
|
13
|
+
if user
|
14
|
+
user.regenerate_verification_token
|
15
|
+
MinimalistAuthenticationMailer.update_password(user).deliver_now
|
16
|
+
end
|
17
|
+
# always display notice even if the user was not found to prevent leaking user emails
|
18
|
+
redirect_to new_session_path, notice: "Password reset instructions were mailed to #{email_params[:email]}"
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def user
|
24
|
+
@user ||= MinimalistAuthentication.configuration.user_model.active.email_verified.find_by(email_params)
|
25
|
+
end
|
26
|
+
|
27
|
+
def email_params
|
28
|
+
params.require(:user).permit(:email)
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class PasswordsController < ApplicationController
|
2
|
+
skip_before_action :authorization_required
|
3
|
+
|
4
|
+
layout 'sessions'
|
5
|
+
|
6
|
+
# From for user to update password
|
7
|
+
def edit
|
8
|
+
redirect_to(new_session_path) unless user.matches_verification_token?(token)
|
9
|
+
# render passwords/edit.html.erb
|
10
|
+
end
|
11
|
+
|
12
|
+
# Update user's password
|
13
|
+
def update
|
14
|
+
if user.secure_update(token, password_params.merge(password_required: true))
|
15
|
+
redirect_to new_session_path, notice: 'Password successfully updated'
|
16
|
+
else
|
17
|
+
render :edit
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def user
|
24
|
+
@user ||= User.find(params[:user_id])
|
25
|
+
end
|
26
|
+
|
27
|
+
def token
|
28
|
+
@token ||= params[:token]
|
29
|
+
end
|
30
|
+
|
31
|
+
def password_params
|
32
|
+
params.require(:user).permit(:password, :password_confirmation)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class MinimalistAuthenticationMailer < ApplicationMailer
|
2
|
+
def verify_email(user)
|
3
|
+
@verify_email_link = email_verification_url(token: user.verification_token)
|
4
|
+
send_to(user, 'Email Address Verification')
|
5
|
+
end
|
6
|
+
|
7
|
+
def update_password(user)
|
8
|
+
@edit_password_link = edit_user_password_url(user, token: user.verification_token)
|
9
|
+
send_to(user, 'Update Password')
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def send_to(user, subject)
|
15
|
+
@user = user
|
16
|
+
mail to: @user.email, subject: prefixed_subject(subject)
|
17
|
+
end
|
18
|
+
|
19
|
+
def prefixed_subject(subject)
|
20
|
+
"#{MinimalistAuthentication.configuration.email_prefix} #{subject}"
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<h2>Please verify your email address</h2>
|
2
|
+
|
3
|
+
<p>
|
4
|
+
<strong><%= current_user.email %></strong>
|
5
|
+
<em><%= link_to('change', edit_email_path) %></em>
|
6
|
+
</p>
|
7
|
+
|
8
|
+
<%= form_tag email_verification_path do |form| %>
|
9
|
+
<%= submit_tag 'Send Verification Email' %>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<p>Verifying your email will allow you to receive confidential messages and reset your password.</p>
|
13
|
+
|
14
|
+
<%= link_to('Skip Email Verification', dashboard_path) %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<h1>Email Verification</h1>
|
2
|
+
|
3
|
+
<% if current_user.email_verified? %>
|
4
|
+
<h2>Your email address has been verified</h2>
|
5
|
+
<% else %>
|
6
|
+
<h2>Email address verification failed</h2>
|
7
|
+
<% end %>
|
8
|
+
<h2><%= current_user.email %></h2>
|
9
|
+
|
10
|
+
<%= link_to('Go to Dashboard', dashboard_path) %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<h1>Email Update</h1>
|
2
|
+
|
3
|
+
<h2>Please update your email address</h2>
|
4
|
+
|
5
|
+
<%= form_for(current_user, as: :user, url: email_path) do |form| %>
|
6
|
+
<%= form.text_field :email %>
|
7
|
+
<%= form.submit 'Update' %>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
<p>Providing your email will allow you to receive confidential messages and reset your password.</p>
|
11
|
+
|
12
|
+
<%= link_to('Skip Email Update', dashboard_path) %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= yield %>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<h1>Request Password Reset</h1>
|
2
|
+
|
3
|
+
<p>
|
4
|
+
Enter your email address we'll send you a link to reset your password.
|
5
|
+
</p>
|
6
|
+
|
7
|
+
<%= form_for @user, as: :user, url: password_reset_path do |form| %>
|
8
|
+
<div>
|
9
|
+
<%= form.label :email %>
|
10
|
+
<%= form.text_field :email %>
|
11
|
+
</div>
|
12
|
+
<%= form.submit 'Reset Password' %>
|
13
|
+
<% end %>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<h1>Edit Password</h1>
|
2
|
+
|
3
|
+
<%= form_for @user, as: :user, url: user_password_path(@user, token: @token), html: { method: :put } do |form| %>
|
4
|
+
<div>
|
5
|
+
<%= form.label :password %>
|
6
|
+
<%= form.password_field :password %>
|
7
|
+
</div>
|
8
|
+
<div>
|
9
|
+
<%= form.label :password_confirmation %>
|
10
|
+
<%= form.password_field :password_confirmation %>
|
11
|
+
</div>
|
12
|
+
<%= form.submit 'Update Password' %>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<div class="field_with_errors" style: 'border-width:5px;'>
|
16
|
+
testing
|
17
|
+
</div>
|
@@ -1,5 +1,11 @@
|
|
1
|
-
<%= form_for
|
2
|
-
|
3
|
-
|
1
|
+
<%= form_for @user, url: session_path do |form| %>
|
2
|
+
<div>
|
3
|
+
<%= form.label :email %>
|
4
|
+
<%= form.text_field :email %>
|
5
|
+
</div>
|
6
|
+
<div>
|
7
|
+
<%= form.label :password %>
|
8
|
+
<%= form.password_field :password %>
|
9
|
+
</div>
|
4
10
|
<%= form.submit 'Log in' %>
|
5
11
|
<% end %>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
en:
|
2
|
+
minimalist_authentication_mailer:
|
3
|
+
update_password:
|
4
|
+
opening: 'Please click the link below to update your password:'
|
5
|
+
verify_email:
|
6
|
+
opening: "Please click the link below to complete your email verification:"
|
7
|
+
closing: 'If you did not request email verification you can safely ignore this message.'
|
data/config/routes.rb
CHANGED
@@ -1,2 +1,10 @@
|
|
1
1
|
Rails.application.routes.draw do
|
2
|
+
resources :user, only: [] do
|
3
|
+
resource :password, only: %i(edit update)
|
4
|
+
end
|
5
|
+
|
6
|
+
resource :password_reset, only: %i(new create)
|
7
|
+
|
8
|
+
resource :email, only: %i(edit update)
|
9
|
+
resource :email_verification, only: %i(new create show)
|
2
10
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'minimalist_authentication/engine'
|
2
2
|
require 'minimalist_authentication/configuration'
|
3
3
|
require 'minimalist_authentication/user'
|
4
|
+
require 'minimalist_authentication/verifiable_token'
|
5
|
+
require 'minimalist_authentication/email_verification'
|
4
6
|
require 'minimalist_authentication/password'
|
5
7
|
require 'minimalist_authentication/null_password'
|
6
8
|
require 'minimalist_authentication/controller'
|
@@ -32,11 +32,37 @@ module MinimalistAuthentication
|
|
32
32
|
# Note: validate_email_presence is only checked if validate_email is true.
|
33
33
|
attr_accessor :validate_email_presence
|
34
34
|
|
35
|
+
# Check for users email at login and request if blank. Only useful if using
|
36
|
+
# username to login and users might not have an email set.
|
37
|
+
# Defaults to true
|
38
|
+
attr_accessor :request_email
|
39
|
+
|
40
|
+
# Vefify users email address at login.
|
41
|
+
# Defaults to true.
|
42
|
+
attr_accessor :verify_email
|
43
|
+
|
44
|
+
# Where to route users after a successful login.
|
45
|
+
# Defaults to :root_path
|
46
|
+
attr_accessor :login_redirect_path
|
47
|
+
|
48
|
+
# Where to route users after logging out.
|
49
|
+
# Defaults to :new_session_path
|
50
|
+
attr_accessor :logout_redirect_path
|
51
|
+
|
52
|
+
# Email subject prefix for MinimalistAuthenticationMailer messages
|
53
|
+
# Defaults to application name
|
54
|
+
attr_accessor :email_prefix
|
55
|
+
|
35
56
|
def initialize
|
36
57
|
self.user_model_name = '::User'
|
37
58
|
self.session_key = :user_id
|
38
59
|
self.validate_email = true
|
39
60
|
self.validate_email_presence = true
|
61
|
+
self.request_email = true
|
62
|
+
self.verify_email = true
|
63
|
+
self.login_redirect_path = :root_path
|
64
|
+
self.logout_redirect_path = :new_session_path
|
65
|
+
self.email_prefix = default_email_prefix
|
40
66
|
end
|
41
67
|
|
42
68
|
# Returns the user_model class
|
@@ -45,5 +71,11 @@ module MinimalistAuthentication
|
|
45
71
|
def user_model
|
46
72
|
@user_model ||= user_model_name.constantize
|
47
73
|
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def default_email_prefix
|
78
|
+
"[#{Rails.application.engine_name.gsub(/_application\z/, '').titleize}]"
|
79
|
+
end
|
48
80
|
end
|
49
81
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module MinimalistAuthentication
|
2
|
+
module EmailVerification
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_save :clear_email_verification, if: ->(user) { user.email_changed? }
|
7
|
+
|
8
|
+
scope :email_verified, -> { where('LENGTH(email) > 2').where.not(email_verified_at: nil) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def needs_email_set?
|
12
|
+
request_email_enabled? && email.blank?
|
13
|
+
end
|
14
|
+
|
15
|
+
def needs_email_verification?
|
16
|
+
email_verification_enabled? && email.present? && email_verified_at.blank?
|
17
|
+
end
|
18
|
+
|
19
|
+
def email_verified?
|
20
|
+
email.present? && email_verified_at.present?
|
21
|
+
end
|
22
|
+
|
23
|
+
def verify_email(token)
|
24
|
+
secure_update(token, email_verified_at: Time.zone.now)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def request_email_enabled?
|
30
|
+
MinimalistAuthentication.configuration.request_email
|
31
|
+
end
|
32
|
+
|
33
|
+
def email_verification_enabled?
|
34
|
+
MinimalistAuthentication.configuration.verify_email
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear_email_verification
|
38
|
+
self.email_verified_at = nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -8,7 +8,7 @@ module MinimalistAuthentication
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def new
|
11
|
-
|
11
|
+
new_user
|
12
12
|
end
|
13
13
|
|
14
14
|
def create
|
@@ -16,7 +16,7 @@ module MinimalistAuthentication
|
|
16
16
|
scrub_session!
|
17
17
|
authenticated_user.logged_in
|
18
18
|
session[MinimalistAuthentication.configuration.session_key] = authenticated_user.id
|
19
|
-
after_authentication_success
|
19
|
+
set_or_verify_email || after_authentication_success
|
20
20
|
return
|
21
21
|
else
|
22
22
|
after_authentication_failure
|
@@ -31,6 +31,10 @@ module MinimalistAuthentication
|
|
31
31
|
|
32
32
|
private
|
33
33
|
|
34
|
+
def new_user
|
35
|
+
@user ||= MinimalistAuthentication.configuration.user_model.new
|
36
|
+
end
|
37
|
+
|
34
38
|
def authenticated_user
|
35
39
|
@authenticated_user ||= MinimalistAuthentication.configuration.user_model.authenticate(user_params)
|
36
40
|
end
|
@@ -39,12 +43,28 @@ module MinimalistAuthentication
|
|
39
43
|
@user_params ||= params.require(:user).permit(:email, :username, :password)
|
40
44
|
end
|
41
45
|
|
46
|
+
def set_or_verify_email
|
47
|
+
if authenticated_user.needs_email_set?
|
48
|
+
redirect_to edit_email_path
|
49
|
+
elsif authenticated_user.needs_email_verification? && !attempting_to_verify?
|
50
|
+
redirect_to new_email_verification_path
|
51
|
+
else
|
52
|
+
false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
42
56
|
def after_authentication_success
|
43
57
|
redirect_back_or_default(login_redirect_to)
|
44
58
|
end
|
45
59
|
|
60
|
+
def attempting_to_verify?
|
61
|
+
# check if user is attpting to verify their email
|
62
|
+
session['return_to'].to_s[/token/]
|
63
|
+
end
|
64
|
+
|
46
65
|
def after_authentication_failure
|
47
66
|
flash.now[:alert] = "Couldn't log you in as '#{user_params[:email] || user_params[:username]}'"
|
67
|
+
new_user
|
48
68
|
render :new
|
49
69
|
end
|
50
70
|
|
@@ -55,11 +75,11 @@ module MinimalistAuthentication
|
|
55
75
|
end
|
56
76
|
|
57
77
|
def login_redirect_to
|
58
|
-
|
78
|
+
send(MinimalistAuthentication.configuration.login_redirect_path)
|
59
79
|
end
|
60
80
|
|
61
81
|
def logout_redirect_to
|
62
|
-
|
82
|
+
send(MinimalistAuthentication.configuration.logout_redirect_path)
|
63
83
|
end
|
64
84
|
end
|
65
85
|
end
|
@@ -4,32 +4,37 @@ module MinimalistAuthentication
|
|
4
4
|
module User
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
-
GUEST_USER_EMAIL
|
8
|
-
EMAIL_REGEX
|
7
|
+
GUEST_USER_EMAIL = 'guest'
|
8
|
+
EMAIL_REGEX = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
|
9
|
+
PASSWORD_MIN = 8
|
10
|
+
PASSWORD_MAX = 40
|
9
11
|
|
10
12
|
included do
|
11
13
|
# Stores the plain text password.
|
12
14
|
attr_accessor :password
|
13
15
|
|
16
|
+
# Force validations for a blank password.
|
17
|
+
attr_accessor :password_required
|
18
|
+
|
14
19
|
# Hashes and stores the password on save.
|
15
20
|
before_save :hash_password
|
16
21
|
|
17
22
|
# Email validations
|
18
|
-
validates_presence_of :email,
|
19
|
-
validates_uniqueness_of :email, allow_blank: true,
|
20
|
-
validates_format_of :email, allow_blank: true, with: EMAIL_REGEX,
|
23
|
+
validates_presence_of :email, if: :validate_email_presence?
|
24
|
+
validates_uniqueness_of :email, allow_blank: true, if: :validate_email?
|
25
|
+
validates_format_of :email, allow_blank: true, with: EMAIL_REGEX, if: :validate_email?
|
21
26
|
|
22
27
|
# Password validations
|
23
|
-
validates_presence_of :password,
|
24
|
-
validates_confirmation_of :password,
|
25
|
-
validates_length_of :password, within:
|
28
|
+
validates_presence_of :password, if: :validate_password?
|
29
|
+
validates_confirmation_of :password, if: :validate_password?
|
30
|
+
validates_length_of :password, within: PASSWORD_MIN..PASSWORD_MAX, if: :validate_password?
|
26
31
|
|
27
32
|
# Active scope
|
28
33
|
scope :active, ->(active = true) { where active: active }
|
29
34
|
end
|
30
35
|
|
31
36
|
module ClassMethods
|
32
|
-
# Authenticates a user form the params
|
37
|
+
# Authenticates a user form the params provided. Expects a params hash with
|
33
38
|
# email or username and passwod keys.
|
34
39
|
# Params examples:
|
35
40
|
# { email: 'user@example.com', password: 'abc123' }
|
@@ -103,9 +108,10 @@ module MinimalistAuthentication
|
|
103
108
|
end
|
104
109
|
|
105
110
|
# Requre password for active users that either do no have a password hash
|
106
|
-
# stored OR are attempting to set a new password.
|
111
|
+
# stored OR are attempting to set a new password. Set **password_required**
|
112
|
+
# to true to force validations even when the password field is blank.
|
107
113
|
def validate_password?
|
108
|
-
active? && (password_hash.blank? || password.present?)
|
114
|
+
active? && (password_hash.blank? || password.present? || password_required)
|
109
115
|
end
|
110
116
|
|
111
117
|
# Validate email for active users.
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module MinimalistAuthentication
|
2
|
+
module VerifiableToken
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
TOKEN_EXPIRATION_HOURS = 6
|
6
|
+
|
7
|
+
# generate secure verification_token and record generation time
|
8
|
+
def regenerate_verification_token
|
9
|
+
update_token
|
10
|
+
end
|
11
|
+
|
12
|
+
def secure_update(token, attributes)
|
13
|
+
if matches_verification_token?(token)
|
14
|
+
update(attributes) && clear_token
|
15
|
+
else
|
16
|
+
errors.add(:base, 'Verfication token check failed')
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def matches_verification_token?(token)
|
22
|
+
verification_token_valid? && secure_match?(token)
|
23
|
+
end
|
24
|
+
|
25
|
+
def verification_token_valid?
|
26
|
+
return false if verification_token.blank? || verification_token_generated_at.blank?
|
27
|
+
verification_token_generated_at > TOKEN_EXPIRATION_HOURS.hours.ago
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def clear_token
|
33
|
+
update_token(token: nil, time: nil)
|
34
|
+
end
|
35
|
+
|
36
|
+
def update_token(token: self.class.generate_unique_secure_token, time: Time.now.utc)
|
37
|
+
update!(
|
38
|
+
verification_token: token,
|
39
|
+
verification_token_generated_at: time
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Compare the tokens in a time-constant manner, to mitigate timing attacks.
|
44
|
+
def secure_match?(token)
|
45
|
+
ActiveSupport::SecurityUtils.secure_compare(
|
46
|
+
::Digest::SHA256.hexdigest(token),
|
47
|
+
::Digest::SHA256.hexdigest(verification_token)
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: minimalist_authentication
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Baldwin
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-
|
12
|
+
date: 2017-10-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -71,19 +71,39 @@ files:
|
|
71
71
|
- README.md
|
72
72
|
- Rakefile
|
73
73
|
- app/assets/config/minimalist_authentication_manifest.js
|
74
|
+
- app/controllers/email_verifications_controller.rb
|
75
|
+
- app/controllers/emails_controller.rb
|
76
|
+
- app/controllers/password_resets_controller.rb
|
77
|
+
- app/controllers/passwords_controller.rb
|
78
|
+
- app/mailers/application_mailer.rb
|
79
|
+
- app/mailers/minimalist_authentication_mailer.rb
|
80
|
+
- app/views/email_verifications/new.html.erb
|
81
|
+
- app/views/email_verifications/show.html.erb
|
82
|
+
- app/views/emails/edit.html.erb
|
83
|
+
- app/views/layouts/mailer.html.erb
|
84
|
+
- app/views/layouts/mailer.text.erb
|
85
|
+
- app/views/minimalist_authentication_mailer/update_password.html.erb
|
86
|
+
- app/views/minimalist_authentication_mailer/update_password.text.erb
|
87
|
+
- app/views/minimalist_authentication_mailer/verify_email.html.erb
|
88
|
+
- app/views/minimalist_authentication_mailer/verify_email.text.erb
|
89
|
+
- app/views/password_resets/new.html.erb
|
90
|
+
- app/views/passwords/edit.html.erb
|
74
91
|
- app/views/sessions/_form.html.erb
|
75
92
|
- app/views/sessions/new.html.erb
|
93
|
+
- config/locales/minimalist_authentication.en.yml
|
76
94
|
- config/routes.rb
|
77
95
|
- lib/minimalist_authentication.rb
|
78
96
|
- lib/minimalist_authentication/configuration.rb
|
79
97
|
- lib/minimalist_authentication/controller.rb
|
80
98
|
- lib/minimalist_authentication/conversions/merge_password_hash.rb
|
99
|
+
- lib/minimalist_authentication/email_verification.rb
|
81
100
|
- lib/minimalist_authentication/engine.rb
|
82
101
|
- lib/minimalist_authentication/null_password.rb
|
83
102
|
- lib/minimalist_authentication/password.rb
|
84
103
|
- lib/minimalist_authentication/sessions.rb
|
85
104
|
- lib/minimalist_authentication/test_helper.rb
|
86
105
|
- lib/minimalist_authentication/user.rb
|
106
|
+
- lib/minimalist_authentication/verifiable_token.rb
|
87
107
|
- lib/minimalist_authentication/version.rb
|
88
108
|
- lib/tasks/minimalist_authentication_tasks.rake
|
89
109
|
homepage: https://github.com/wwidea/minimalist_authentication
|