minimalist_authentication 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|