minimalist_authentication 3.2.4 → 3.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0e7fbd42fef46be26f68d4df9257963d7f694405da2f863fa0a34d04d4c390d
4
- data.tar.gz: d10c06d41126ff04dc4e09fa3ebfa80c3aa29a479b1893c3c0a8ed583b204da3
3
+ metadata.gz: a00b1f4d3eca783ae2d6f0998b164bf1cc2cb26e2721b807c9c95e5b7c9c1ed4
4
+ data.tar.gz: 9a881ed13f89438464d09f574e6ab24f4a2b6a49483a88ec12b4b1afcc937d89
5
5
  SHA512:
6
- metadata.gz: aea05763f08f292f4464b94ff5c594523203c0d191a8b8ca3e9e3a315873290666c8314c5603f648d05535ddbecd2ef62d65c56925c7b0e7d9332bd236a87a19
7
- data.tar.gz: acfa6f1729a24eb67a3d0d76ec7db12b67c19f4c7b52a81867b63859b3f8fceb2981e4a025a8039fc5d0f47e3de874e7f716c714a8860cf86a4acaa54ea74c38
6
+ metadata.gz: 7001e00701070f34b03aa012841452fa75d58fdab35f5ae0cf551190d50f5c8319f746b71754858fba02f5e12365838d2dff398786895bd5ba9919da0b06575d
7
+ data.tar.gz: 0f82b8cd2b1d47b6b899ee3a31fa4f50cb7ac54b958e3216c3acc13a1303ba5068c3170af7840ede8835130af379286b1ddd8b712a6c6ec81e30c62aa907a4f5
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # MinimalistAuthentication
2
- A Rails authentication gem that takes a minimalist approach. It is designed to be simple to understand, use, and customize for your application.
3
2
 
3
+ A Rails authentication gem that takes a minimalist approach. It is designed to be simple to understand, use, and customize for your application.
4
4
 
5
5
  ## Installation
6
+
6
7
  Add this line to your application's Gemfile:
7
8
 
8
9
  ```ruby
@@ -10,23 +11,27 @@ gem "minimalist_authentication"
10
11
  ```
11
12
 
12
13
  And then run:
14
+
13
15
  ```bash
14
- $ bundle
16
+ bundle
15
17
  ```
16
18
 
17
19
  Create a user model with **email** for an identifier:
20
+
18
21
  ```bash
19
22
  bin/rails generate model user active:boolean email:string password_digest:string last_logged_in_at:datetime
20
23
  ```
21
24
 
22
25
  OR create a user model with **username** for an identifier:
26
+
23
27
  ```bash
24
28
  bin/rails generate model user active:boolean username:string password_digest:string last_logged_in_at:datetime
25
29
  ```
26
30
 
27
-
28
31
  ## Example
32
+
29
33
  Create a Current class that inherits from ActiveSupport::CurrentAttributes with a user attribute (app/models/current.rb)
34
+
30
35
  ```ruby
31
36
  class Current < ActiveSupport::CurrentAttributes
32
37
  attribute :user
@@ -34,6 +39,7 @@ end
34
39
  ```
35
40
 
36
41
  Include MinimalistAuthentication::User in your user model (app/models/user.rb)
42
+
37
43
  ```ruby
38
44
  class User < ApplicationRecord
39
45
  include MinimalistAuthentication::User
@@ -41,6 +47,7 @@ end
41
47
  ```
42
48
 
43
49
  Include MinimalistAuthentication::Controller in your ApplicationController (app/controllers/application.rb)
50
+
44
51
  ```ruby
45
52
  class ApplicationController < ActionController::Base
46
53
  include MinimalistAuthentication::Controller
@@ -48,6 +55,7 @@ end
48
55
  ```
49
56
 
50
57
  Include MinimalistAuthentication::Sessions in your SessionsController (app/controllers/sessions_controller.rb)
58
+
51
59
  ```ruby
52
60
  class SessionsController < ApplicationController
53
61
  include MinimalistAuthentication::Sessions
@@ -55,6 +63,7 @@ end
55
63
  ```
56
64
 
57
65
  Add session to your routes file (config/routes.rb)
66
+
58
67
  ```ruby
59
68
  Rails.application.routes.draw do
60
69
  resource :session, only: %i(new create destroy)
@@ -62,29 +71,35 @@ end
62
71
  ```
63
72
 
64
73
  Include Minimalist::TestHelper in your test helper (test/test_helper.rb)
74
+
65
75
  ```ruby
66
76
  class ActiveSupport::TestCase
67
77
  include MinimalistAuthentication::TestHelper
68
78
  end
69
79
  ```
70
80
 
71
-
72
81
  ## Configuration
82
+
73
83
  Customize the configuration with an initializer. Create a **minimalist_authentication.rb** file in config/initializers.
84
+
74
85
  ```ruby
75
86
  MinimalistAuthentication.configure do |configuration|
76
- configuration.login_redirect_path = :custom_path # default is :root_path
77
- configuration.logout_redirect_path = :custom_path # default is :new_session_path
78
- configuration.request_email = true # default is true
79
- configuration.session_key = :custom_session_key # default is :user_id
80
- configuration.user_model_name = "CustomModelName" # default is "::User"
81
- configuration.validate_email = true # default is true
82
- configuration.validate_email_presence = true # default is true
83
- configuration.verify_email = true # default is true
87
+ configuration.account_setup_duration = 3.days # default: 1.day
88
+ configuration.email_verification_duration = 30.minutes # default: 1.hour
89
+ configuration.login_redirect_path = :custom_path # default: :root_path
90
+ configuration.logout_redirect_path = :custom_path # default: :new_session_path
91
+ configuration.password_reset_duration = 30.minutes # default: 1.hour
92
+ configuration.request_email = true # default: true
93
+ configuration.session_key = :custom_session_key # default: :user_id
94
+ configuration.user_model_name = "CustomModelName" # default: "::User"
95
+ configuration.validate_email = true # default: true
96
+ configuration.validate_email_presence = true # default: true
97
+ configuration.verify_email = true # default: true
84
98
  end
85
99
  ```
86
100
 
87
101
  ### Example with a Person Model
102
+
88
103
  ```ruby
89
104
  MinimalistAuthentication.configure do |configuration|
90
105
  configuration.login_redirect_path = :dashboard_path
@@ -94,18 +109,20 @@ MinimalistAuthentication.configure do |configuration|
94
109
  end
95
110
  ```
96
111
 
97
-
98
112
  ## Fixtures
113
+
99
114
  Use **MinimalistAuthentication::TestHelper::PASSWORD_DIGEST** to create a password_digest for fixture users.
115
+
100
116
  ```yaml
101
117
  example_user:
102
- email: user@example.com
103
- password_digest: <%= MinimalistAuthentication::TestHelper::PASSWORD_DIGEST %>
118
+ email: user@example.com
119
+ password_digest: <%= MinimalistAuthentication::TestHelper::PASSWORD_DIGEST %>
104
120
  ```
105
121
 
106
-
107
122
  ## Email Verification
123
+
108
124
  Include MinimalistAuthentication::EmailVerification in your user model (app/models/user.rb)
125
+
109
126
  ```ruby
110
127
  class User < ApplicationRecord
111
128
  include MinimalistAuthentication::User
@@ -114,18 +131,37 @@ end
114
131
  ```
115
132
 
116
133
  Add the **email_verified_at** column to your user model:
134
+
117
135
  ```bash
118
136
  bin/rails generate migration AddEmailVerifiedAtToUsers email_verified_at:datetime
119
137
  ```
120
138
 
121
-
122
139
  ## Verification Tokens
123
- Verification token support is provided by the ```ActiveRecord::TokenFor#generate_token_for``` method. MinimalistAuthentication includes token definitions for **password_reset** and **email_verification**. These tokens are utilized by the **update_password** and **verify_email** email messages respectively, to allow users to update their passwords and verify their email addresses.
124
140
 
125
- ### Update Password
126
- The **update_password** token expires in 1 hour and is invalidated when the user's password is changed.
141
+ Verification token support is provided by the `ActiveRecord::TokenFor#generate_token_for` method.
142
+ MinimalistAuthentication includes token definitions for **account_setup**, **password_reset**, and **email_verification**.
143
+
144
+ ### Account Setup
145
+
146
+ The **account_setup** token is used for new users to set their initial password.
147
+ The token expires in 1 day and is invalidated when the user's password is changed.
127
148
 
128
149
  #### Example
150
+
151
+ ```ruby
152
+ token = user.generate_token_for(:account_setup)
153
+ User.find_by_token_for(:account_setup, token) # => user
154
+ user.update!(password: "new password")
155
+ User.find_by_token_for(:account_setup, token) # => nil
156
+ ```
157
+
158
+ ### Password Reset
159
+
160
+ The **password_reset** token is used for existing users to reset their password.
161
+ The token expires in 1 hour and is invalidated when the user's password is changed.
162
+
163
+ #### Example
164
+
129
165
  ```ruby
130
166
  token = user.generate_token_for(:password_reset)
131
167
  User.find_by_token_for(:password_reset, token) # => user
@@ -134,9 +170,11 @@ User.find_by_token_for(:password_reset, token) # => nil
134
170
  ```
135
171
 
136
172
  ### Email Verification
173
+
137
174
  The **email_verification** token expires in 1 hour and is invalidated when the user's email is changed.
138
175
 
139
176
  #### Example
177
+
140
178
  ```ruby
141
179
  token = user.generate_token_for(:email_verification)
142
180
  User.find_by_token_for(:email_verification, token) # => user
@@ -144,10 +182,10 @@ user.update!(email: "new_email@example.com")
144
182
  User.find_by_token_for(:email_verification, token) # => nil
145
183
  ```
146
184
 
147
-
148
185
  ## Conversions
149
186
 
150
187
  ### Upgrading to Version 2.0
188
+
151
189
  Pre 2.0 versions of MinimalistAuthentication supported multiple hash algorithms
152
190
  and stored the hashed password and salt as separate fields in the database
153
191
  (crypted_password and salt). The 2.0 version of MinimalistAuthentication
@@ -155,9 +193,11 @@ uses BCrypt to hash passwords and stores the result in the **password_hash** fie
155
193
 
156
194
  To convert from a pre 2.0 version add the **password_hash** to your user model
157
195
  and run the conversion routine.
196
+
158
197
  ```bash
159
198
  bin/rails generate migration AddPasswordHashToUsers password_hash:string
160
199
  ```
200
+
161
201
  ```ruby
162
202
  MinimalistAuthentication::Conversions::MergePasswordHash.run!
163
203
  ```
@@ -166,15 +206,21 @@ When the conversion is complete the **crypted_password**, **salt**, and
166
206
  **using_digest_version** fields can safely be removed.
167
207
 
168
208
  ### Upgrading to Version 3.0
169
- Version 3.0 of MinimalistAuthentication uses the Rails has_secure_password for authentication. This change requires either renaming the **password_hash** column to **password_digest** or adding an alias_attribute to map **password_digest** to **password_hash**.
209
+
210
+ Version 3.0 of MinimalistAuthentication uses the Rails has_secure_password for authentication.
211
+ This change requires either renaming the **password_hash** column to **password_digest** or adding
212
+ an alias_attribute to map **password_digest** to **password_hash**.
170
213
 
171
214
  #### Rename the **password_hash** column to **password_digest**
215
+
172
216
  Add a migration to rename the column in your users table:
217
+
173
218
  ```bash
174
219
  bin/rails generate migration rename_users_password_hash_to_password_digest
175
220
  ```
176
221
 
177
222
  Update the change method:
223
+
178
224
  ```ruby
179
225
  def change
180
226
  rename_column :users, :password_hash, :password_digest
@@ -182,13 +228,15 @@ end
182
228
  ```
183
229
 
184
230
  #### Alternatively, add **alias_attribute** to your user model
231
+
185
232
  ```ruby
186
233
  alias_attribute :password_digest, :password_hash
187
234
  ```
188
235
 
189
236
  ### Upgrading to Version 3.2
190
- The **verification_token** and **verification_token_generated_at** database columns are no longer used and can be safely removed from your user model.
191
237
 
238
+ The **verification_token** and **verification_token_generated_at** database columns are no longer used and can be safely removed from your user model.
192
239
 
193
240
  ## License
194
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT)..
241
+
242
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -3,7 +3,7 @@
3
3
  class EmailVerificationsController < ApplicationController
4
4
  # Verifies the email of the current_user using the provided token
5
5
  def show
6
- current_user.verify_email(params[:token])
6
+ current_user.verify_email_with(params[:token])
7
7
  end
8
8
 
9
9
  # Form for current_user to request an email verification email
@@ -13,7 +13,7 @@ class PasswordResetsController < ApplicationController
13
13
  # Send a password update link to users with a verified email
14
14
  def create
15
15
  if email_valid?
16
- send_update_password_email if user
16
+ send_update_password_email(user)
17
17
 
18
18
  # Always display notice to prevent leaking user emails
19
19
  redirect_to new_session_path, notice: t(".notice", email:)
@@ -29,12 +29,12 @@ class PasswordResetsController < ApplicationController
29
29
  params.dig(:user, :email)
30
30
  end
31
31
 
32
- def send_update_password_email
33
- MinimalistAuthenticationMailer.with(user:).update_password.deliver_now
32
+ def send_update_password_email(user)
33
+ MinimalistAuthenticationMailer.with(user:).update_password.deliver_now if user
34
34
  end
35
35
 
36
36
  def user
37
- @user ||= MinimalistAuthentication.user_model.find_by_verified_email(email:)
37
+ MinimalistAuthentication.user_model.active.find_by(email:)
38
38
  end
39
39
 
40
40
  def email_valid?
@@ -1,41 +1,61 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class PasswordsController < ApplicationController
4
- skip_before_action :authorization_required
4
+ ACTION_TOKEN_PURPOSES = ActiveSupport::HashWithIndifferentAccess.new(
5
+ new: :account_setup,
6
+ create: :account_setup,
7
+ edit: :password_reset,
8
+ update: :password_reset
9
+ ).freeze
10
+
11
+ attr_reader :user
5
12
 
6
- before_action :validate_token, only: %i[edit update]
13
+ skip_before_action :authorization_required
14
+ before_action :authenticate_with_token
7
15
 
8
16
  layout "sessions"
9
17
 
10
- # From for user to update password
18
+ # Set password form
19
+ def new
20
+ # new.html.erb
21
+ end
22
+
23
+ # Sets user password
24
+ def create
25
+ update_password(:new)
26
+ end
27
+
28
+ # Update password form
11
29
  def edit
12
30
  # edit.html.erb
13
31
  end
14
32
 
15
- # Update user's password
33
+ # Resets user password
16
34
  def update
17
- if user.update(password_params)
18
- redirect_to new_session_path, notice: t(".notice")
19
- else
20
- render :edit, status: :unprocessable_content
21
- end
35
+ update_password(:new)
22
36
  end
23
37
 
24
38
  private
25
39
 
26
- def password_params
27
- params.require(:user).permit(:password, :password_confirmation)
40
+ def authenticate_with_token
41
+ @token = params[:token]
42
+ @user = MinimalistAuthentication.user_model.active.find_by_token_for(purpose, @token)
43
+ redirect_to(new_session_path, alert: t(".invalid_token")) unless @user
28
44
  end
29
45
 
30
- def token
31
- @token ||= params[:token]
46
+ def password_params
47
+ params.require(:user).permit(:password, :password_confirmation)
32
48
  end
33
49
 
34
- def user
35
- @user ||= MinimalistAuthentication.user_model.active.find_by_token_for(:password_reset, token)
50
+ def purpose
51
+ ACTION_TOKEN_PURPOSES[action_name]
36
52
  end
37
53
 
38
- def validate_token
39
- redirect_to(new_session_path, alert: t(".invalid_token")) unless user
54
+ def update_password(template)
55
+ if user.verified_update(password_params)
56
+ redirect_to new_session_path, notice: t(".notice")
57
+ else
58
+ render template, status: :unprocessable_content
59
+ end
40
60
  end
41
61
  end
@@ -2,13 +2,17 @@
2
2
 
3
3
  module MinimalistAuthentication
4
4
  module ApplicationHelper
5
+ def ma_change_email_link
6
+ link_to("Change", edit_email_path)
7
+ end
8
+
5
9
  def ma_confirm_password_field(form, options = {})
6
10
  form.password_field(
7
11
  :password_confirmation,
8
12
  options.reverse_merge(
9
13
  autocomplete: "new-password",
10
14
  minlength: MinimalistAuthentication.user_model.password_minimum,
11
- placeholder: t(".password_confirmation.placeholder"),
15
+ placeholder: true,
12
16
  required: true
13
17
  )
14
18
  )
@@ -36,7 +40,7 @@ module MinimalistAuthentication
36
40
  options.reverse_merge(
37
41
  autocomplete: "new-password",
38
42
  minlength: MinimalistAuthentication.user_model.password_minimum,
39
- placeholder: t(".password.placeholder"),
43
+ placeholder: true,
40
44
  required: true
41
45
  )
42
46
  )
@@ -53,6 +57,10 @@ module MinimalistAuthentication
53
57
  )
54
58
  end
55
59
 
60
+ def ma_skip_link
61
+ link_to("Skip", login_redirect_to)
62
+ end
63
+
56
64
  def ma_username_field(form, options = {})
57
65
  form.text_field(
58
66
  :username,
@@ -1,14 +1,12 @@
1
- <h2>Please verify your email address</h2>
1
+ <h2><%= t(".title") %></h2>
2
2
 
3
3
  <p>
4
4
  <strong><%= current_user.email %></strong>
5
- <em><%= link_to('change', edit_email_path) %></em>
5
+ <em><%= ma_change_email_link %></em>
6
6
  </p>
7
7
 
8
- <%= form_tag email_verification_path do |form| %>
9
- <%= submit_tag 'Send Verification Email' %>
10
- <% end %>
8
+ <%= button_to t(".button"), email_verification_path %>
11
9
 
12
- <p>Verifying your email will allow you to receive confidential messages and reset your password.</p>
10
+ <p><%= t(".message") %></p>
13
11
 
14
- <%= link_to('Skip Email Verification', dashboard_path) %>
12
+ <%= ma_skip_link %>
@@ -1,12 +1,12 @@
1
- <h1>Email Update</h1>
1
+ <h1><%= t(".title") %></h1>
2
2
 
3
- <h2>Please update your email address</h2>
3
+ <h2><%= t(".instructions") %></h2>
4
4
 
5
5
  <%= form_with(model: current_user, url: email_path) do |form| %>
6
6
  <%= form.text_field :email %>
7
- <%= form.submit "Update" %>
7
+ <%= form.submit t(".submit") %>
8
8
  <% end %>
9
9
 
10
- <p>Providing your email will allow you to receive confidential messages and reset your password.</p>
10
+ <p><%= t(".message") %></p>
11
11
 
12
- <%= link_to("Skip Email Update", dashboard_path) %>
12
+ <%= ma_skip_link %>
@@ -0,0 +1,16 @@
1
+ <%# locals: (user:, token:, method: nil) %>
2
+
3
+ <%= user.errors.full_messages if user.errors.any? %>
4
+
5
+ <%= form_with(model: user, url: password_path(token: token), method:) do |form| %>
6
+ <div>
7
+ <%= form.label :password %>
8
+ <%= ma_new_password_field(form) %>
9
+ </div>
10
+ <div>
11
+ <%= form.label :password_confirmation %>
12
+ <%= ma_confirm_password_field(form) %>
13
+ </div>
14
+ <%= form.submit t(".submit") %>
15
+ <% end %>
16
+
@@ -2,16 +2,4 @@
2
2
 
3
3
  <p><%= t(".instructions") %></p>
4
4
 
5
- <%= @user.errors.full_messages if @user.errors.any? %>
6
-
7
- <%= form_with model: @user, url: password_path(token: @token) do |form| %>
8
- <div>
9
- <%= form.label :password %>
10
- <%= ma_new_password_field(form) %>
11
- </div>
12
- <div>
13
- <%= form.label :password_confirmation %>
14
- <%= ma_confirm_password_field(form) %>
15
- </div>
16
- <%= form.submit t(".submit") %>
17
- <% end %>
5
+ <%= render("form", user: @user, token: @token) %>
@@ -0,0 +1,5 @@
1
+ <h1><%= t(".title") %></h1>
2
+
3
+ <p><%= t(".instructions") %></p>
4
+
5
+ <%= render("form", user: @user, token: @token, method: :post) %>
@@ -2,7 +2,16 @@ en:
2
2
  email_verifications:
3
3
  create:
4
4
  notice: Verification email sent to %{email}, follow the instructions to complete verification. Thank you!
5
+ new:
6
+ button: Send Verification Email
7
+ message: Verifying your email will allow you to receive confidential messages.
8
+ title: Please verify your email address
5
9
  emails:
10
+ edit:
11
+ instructions: Please update your email address
12
+ message: Providing your email will allow you to receive confidential messages and reset your password.
13
+ submit: Update
14
+ title: Email Update
6
15
  update:
7
16
  notice: Email successfully updated
8
17
  minimalist_authentication_mailer:
@@ -26,15 +35,14 @@ en:
26
35
  passwords:
27
36
  edit:
28
37
  instructions: Please enter your new password.
29
- password:
30
- placeholder: New password
31
- password_confirmation:
32
- placeholder: Confirm password
33
- submit: Reset Password
34
38
  title: Reset Password
35
- invalid_token: Your password reset link has expired. Please request a new one to continue.
36
- update:
37
- notice: Password successfully updated
39
+ form:
40
+ submit: Save Password
41
+ invalid_token: Your link has expired or is invalid. Please request a new one to continue.
42
+ new:
43
+ instructions: Choose a secure password to complete your account setup.
44
+ title: Complete Your Account Setup
45
+ notice: Password successfully updated
38
46
  sessions:
39
47
  create:
40
48
  alert: Couldn't log you in as %{identifier}
data/config/routes.rb CHANGED
@@ -4,5 +4,5 @@ Rails.application.routes.draw do
4
4
  resource :email_verification, only: %i[show new create]
5
5
  resource :email, only: %i[edit update]
6
6
  resource :password_reset, only: %i[new create]
7
- resource :password, only: %i[edit update]
7
+ resource :password, only: %i[new create edit update]
8
8
  end
@@ -17,50 +17,42 @@ module MinimalistAuthentication
17
17
  end
18
18
 
19
19
  class Configuration
20
+ include ActiveModel::Attributes
21
+
22
+ # The duration for which the account_setup token is valid.
23
+ attribute :account_setup_duration, default: 1.day
24
+
25
+ # The duration for which the email_verification token is valid.
26
+ attribute :email_verification_duration, default: 1.hour
27
+
28
+ # Where to route users after a successful login.
29
+ attribute :login_redirect_path, default: :root_path
30
+
31
+ # Where to route users after logging out.
32
+ attribute :logout_redirect_path, default: :new_session_path
33
+
34
+ # The duration for which the password_reset token is valid.
35
+ attribute :password_reset_duration, default: 1.hour
36
+
37
+ # Check for users email at login and request if blank. Only useful if using
38
+ # username to login and users might not have an email set.
39
+ attribute :request_email, :boolean, default: true
40
+
20
41
  # The session_key used to store the current_user id.
21
- # Defaults to :user_id
22
- attr_accessor :session_key
42
+ attribute :session_key, default: :user_id
23
43
 
24
44
  # The application user class name
25
- # Defaults to '::User'
26
- attr_accessor :user_model_name
45
+ attribute :user_model_name, :string, default: "::User"
27
46
 
28
47
  # Toggle all email validations.
29
- # Defaults to true.
30
- attr_accessor :validate_email
48
+ attribute :validate_email, :boolean, default: true
31
49
 
32
50
  # Toggle email presence validation.
33
- # Defaults to true.
34
51
  # Note: validate_email_presence is only checked if validate_email is true.
35
- attr_accessor :validate_email_presence
36
-
37
- # Check for users email at login and request if blank. Only useful if using
38
- # username to login and users might not have an email set.
39
- # Defaults to true
40
- attr_accessor :request_email
52
+ attribute :validate_email_presence, :boolean, default: true
41
53
 
42
54
  # Verify users email address at login.
43
- # Defaults to true.
44
- attr_accessor :verify_email
45
-
46
- # Where to route users after a successful login.
47
- # Defaults to :root_path
48
- attr_accessor :login_redirect_path
49
-
50
- # Where to route users after logging out.
51
- # Defaults to :new_session_path
52
- attr_accessor :logout_redirect_path
53
-
54
- def initialize
55
- self.user_model_name = "::User"
56
- self.session_key = :user_id
57
- self.validate_email = true
58
- self.validate_email_presence = true
59
- self.request_email = true
60
- self.verify_email = true
61
- self.login_redirect_path = :root_path
62
- self.logout_redirect_path = :new_session_path
63
- end
55
+ attribute :verify_email, :boolean, default: true
64
56
 
65
57
  # Clear the user_model class
66
58
  def clear_user_model
@@ -14,7 +14,7 @@ module MinimalistAuthentication
14
14
 
15
15
  helper MinimalistAuthentication::ApplicationHelper
16
16
 
17
- helper_method :current_user, :logged_in?, :authorized?
17
+ helper_method :authorized?, :current_user, :logged_in?, :login_redirect_to
18
18
  end
19
19
 
20
20
  # Returns true if the user is logged in
@@ -33,6 +33,11 @@ module MinimalistAuthentication
33
33
  current_user.present?
34
34
  end
35
35
 
36
+ # Returns the path to redirect to after login
37
+ def login_redirect_to
38
+ public_send(MinimalistAuthentication.configuration.login_redirect_path)
39
+ end
40
+
36
41
  # Logs in a user by setting the session key and updating the Current user
37
42
  # Should only be called after a successful authentication
38
43
  def update_current_user(user)
@@ -5,7 +5,7 @@ module MinimalistAuthentication
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- generates_token_for :email_verification, expires_in: 1.hour do
8
+ generates_token_for :email_verification, expires_in: email_verification_duration do
9
9
  email
10
10
  end
11
11
 
@@ -15,6 +15,8 @@ module MinimalistAuthentication
15
15
  end
16
16
 
17
17
  module ClassMethods
18
+ delegate :email_verification_duration, :password_reset_duration, to: "MinimalistAuthentication.configuration"
19
+
18
20
  def email_verified
19
21
  MinimalistAuthentication.deprecator.warn(<<-MSG.squish)
20
22
  Calling #email_verified is deprecated.
@@ -40,8 +42,12 @@ module MinimalistAuthentication
40
42
  email_verification_enabled? && email.present? && email_verified_at.blank?
41
43
  end
42
44
 
43
- def verify_email(token)
44
- touch(:email_verified_at) if token_owner?(:email_verification, token)
45
+ def verified_update(attributes)
46
+ super(attributes.merge(email_verified_at: Time.current))
47
+ end
48
+
49
+ def verify_email_with(token)
50
+ verify_email if token_owner?(:email_verification, token)
45
51
  end
46
52
 
47
53
  private
@@ -57,5 +63,9 @@ module MinimalistAuthentication
57
63
  def request_email_enabled?
58
64
  MinimalistAuthentication.configuration.request_email
59
65
  end
66
+
67
+ def verify_email
68
+ touch(:email_verified_at)
69
+ end
60
70
  end
61
71
  end
@@ -83,10 +83,6 @@ module MinimalistAuthentication
83
83
  user_params.values_at(*MinimalistAuthentication::Authenticator::LOGIN_FIELDS).compact.first
84
84
  end
85
85
 
86
- def login_redirect_to
87
- send(MinimalistAuthentication.configuration.login_redirect_path)
88
- end
89
-
90
86
  def logout_redirect_to
91
87
  send(MinimalistAuthentication.configuration.logout_redirect_path)
92
88
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module MinimalistAuthentication
4
4
  module TestHelper
5
+ NEW_PASSWORD = "abcdef123456"
5
6
  PASSWORD = "test-password"
6
7
  PASSWORD_DIGEST = BCrypt::Password.create(PASSWORD, cost: BCrypt::Engine::MIN_COST)
7
8
 
@@ -7,10 +7,18 @@ module MinimalistAuthentication
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- has_secure_password
10
+ has_secure_password reset_token: { expires_in: password_reset_duration }
11
11
 
12
- generates_token_for :password_reset, expires_in: 1.hour do
13
- password_salt.last(10)
12
+ # Tracks if password was explicitly set. Used to conditionally require password presence.
13
+ attribute :password_updated, :boolean, default: false
14
+
15
+ define_method(:password=) do |value|
16
+ self.password_updated = true
17
+ super(value)
18
+ end
19
+
20
+ generates_token_for :account_setup, expires_in: account_setup_duration do
21
+ password_salt&.last(10)
14
22
  end
15
23
 
16
24
  # Email validations
@@ -39,6 +47,8 @@ module MinimalistAuthentication
39
47
  end
40
48
 
41
49
  module ClassMethods
50
+ delegate :account_setup_duration, :password_reset_duration, to: "MinimalistAuthentication.configuration"
51
+
42
52
  # Finds a user by their id and returns the user if they are enabled.
43
53
  # Returns nil if the user is not found or not enabled.
44
54
  def find_enabled(id)
@@ -67,9 +77,9 @@ module MinimalistAuthentication
67
77
  active?
68
78
  end
69
79
 
70
- # Remove the has_secure_password password blank error if user is inactive.
80
+ # Remove the has_secure_password password blank error when password is not required.
71
81
  def errors
72
- super.tap { |errors| errors.delete(:password, :blank) if inactive? }
82
+ super.tap { |errors| errors.delete(:password, :blank) unless password_required? }
73
83
  end
74
84
 
75
85
  # Returns true if password matches the hashed_password, otherwise returns false.
@@ -100,8 +110,18 @@ module MinimalistAuthentication
100
110
  update_column(:last_logged_in_at, Time.current)
101
111
  end
102
112
 
113
+ # Overridden by EmailVerification to verify email upon update.
114
+ def verified_update(*)
115
+ update(*)
116
+ end
117
+
103
118
  private
104
119
 
120
+ # Password presence is required for active users who are updating their password.
121
+ def password_required?
122
+ active? && password_updated?
123
+ end
124
+
105
125
  # Return true if the user matches the owner of the provided token.
106
126
  def token_owner?(purpose, token)
107
127
  self.class.find_by_token_for(purpose, token) == self
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MinimalistAuthentication
4
- VERSION = "3.2.4"
4
+ VERSION = "3.3.0"
5
5
  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: 3.2.4
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Baldwin
@@ -73,7 +73,9 @@ files:
73
73
  - app/views/minimalist_authentication_mailer/verify_email.html.erb
74
74
  - app/views/minimalist_authentication_mailer/verify_email.text.erb
75
75
  - app/views/password_resets/new.html.erb
76
+ - app/views/passwords/_form.html.erb
76
77
  - app/views/passwords/edit.html.erb
78
+ - app/views/passwords/new.html.erb
77
79
  - app/views/sessions/_form.html.erb
78
80
  - app/views/sessions/new.html.erb
79
81
  - config/locales/minimalist_authentication.en.yml
@@ -103,7 +105,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
105
  requirements:
104
106
  - - ">="
105
107
  - !ruby/object:Gem::Version
106
- version: 3.1.0
108
+ version: 3.2.0
107
109
  required_rubygems_version: !ruby/object:Gem::Requirement
108
110
  requirements:
109
111
  - - ">="