minimalist_authentication 3.2.4 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +72 -24
- data/app/controllers/email_verifications_controller.rb +1 -1
- data/app/controllers/password_resets_controller.rb +8 -5
- data/app/controllers/passwords_controller.rb +38 -17
- data/app/helpers/minimalist_authentication/application_helper.rb +10 -2
- data/app/views/email_verifications/new.html.erb +5 -7
- data/app/views/emails/edit.html.erb +5 -5
- data/app/views/passwords/_form.html.erb +16 -0
- data/app/views/passwords/edit.html.erb +1 -13
- data/app/views/passwords/new.html.erb +5 -0
- data/config/locales/minimalist_authentication.en.yml +18 -8
- data/config/routes.rb +1 -1
- data/lib/minimalist_authentication/configuration.rb +26 -34
- data/lib/minimalist_authentication/controller.rb +18 -1
- data/lib/minimalist_authentication/email_verification.rb +13 -3
- data/lib/minimalist_authentication/sessions.rb +5 -5
- data/lib/minimalist_authentication/test_helper.rb +1 -0
- data/lib/minimalist_authentication/user.rb +25 -5
- data/lib/minimalist_authentication/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30a0e5b2c5f11655889d24977dc758a7742a83621143a0a217838277d115325d
|
|
4
|
+
data.tar.gz: 86833ecb6f4e387fa385f3f5de89f0b17073ee291f706626a543c3858879d90b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 401499f54f4973a1cb93944728cd8fa8a8538eb328a41ff76de290050a437a60b37543c54189154029ee6e6d3b144cbd55612f4000079f2725065cce409f6c14
|
|
7
|
+
data.tar.gz: ece50dc5d0dd86534fec1225370232dc7029a039228fc3047379de0505d99a426cf8c036c7e918c10569e6499a74c49bf1047444be0009cf1a552c5879d0be01
|
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
|
-
|
|
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.
|
|
77
|
-
configuration.
|
|
78
|
-
configuration.
|
|
79
|
-
configuration.
|
|
80
|
-
configuration.
|
|
81
|
-
configuration.
|
|
82
|
-
configuration.
|
|
83
|
-
configuration.
|
|
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:
|
|
103
|
-
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
|
-
|
|
126
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
@@ -5,7 +5,10 @@ class PasswordResetsController < ApplicationController
|
|
|
5
5
|
|
|
6
6
|
layout "sessions"
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# Limit create requests by ip address
|
|
9
|
+
limit_creations
|
|
10
|
+
|
|
11
|
+
# Password reset request form
|
|
9
12
|
def new
|
|
10
13
|
# new.html.erb
|
|
11
14
|
end
|
|
@@ -13,7 +16,7 @@ class PasswordResetsController < ApplicationController
|
|
|
13
16
|
# Send a password update link to users with a verified email
|
|
14
17
|
def create
|
|
15
18
|
if email_valid?
|
|
16
|
-
send_update_password_email
|
|
19
|
+
send_update_password_email(user)
|
|
17
20
|
|
|
18
21
|
# Always display notice to prevent leaking user emails
|
|
19
22
|
redirect_to new_session_path, notice: t(".notice", email:)
|
|
@@ -29,12 +32,12 @@ class PasswordResetsController < ApplicationController
|
|
|
29
32
|
params.dig(:user, :email)
|
|
30
33
|
end
|
|
31
34
|
|
|
32
|
-
def send_update_password_email
|
|
33
|
-
MinimalistAuthenticationMailer.with(user:).update_password.deliver_now
|
|
35
|
+
def send_update_password_email(user)
|
|
36
|
+
MinimalistAuthenticationMailer.with(user:).update_password.deliver_now if user
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
def user
|
|
37
|
-
|
|
40
|
+
MinimalistAuthentication.user_model.active.find_by(email:)
|
|
38
41
|
end
|
|
39
42
|
|
|
40
43
|
def email_valid?
|
|
@@ -1,41 +1,62 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class PasswordsController < ApplicationController
|
|
4
|
-
|
|
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
|
-
|
|
13
|
+
skip_before_action :authorization_required
|
|
14
|
+
before_action :authenticate_with_token
|
|
7
15
|
|
|
8
16
|
layout "sessions"
|
|
9
17
|
|
|
10
|
-
#
|
|
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
|
-
#
|
|
33
|
+
# Resets user password
|
|
16
34
|
def update
|
|
17
|
-
|
|
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
|
|
27
|
-
params
|
|
40
|
+
def authenticate_with_token
|
|
41
|
+
@token = params[:token]
|
|
42
|
+
@user = MinimalistAuthentication.user_model.active.find_by_token_for!(purpose, @token)
|
|
43
|
+
rescue ActiveRecord::RecordNotFound, ActiveSupport::MessageVerifier::InvalidSignature
|
|
44
|
+
redirect_to(new_session_path, alert: t(".invalid_token"))
|
|
28
45
|
end
|
|
29
46
|
|
|
30
|
-
def
|
|
31
|
-
|
|
47
|
+
def password_params
|
|
48
|
+
params.require(:user).permit(:password, :password_confirmation)
|
|
32
49
|
end
|
|
33
50
|
|
|
34
|
-
def
|
|
35
|
-
|
|
51
|
+
def purpose
|
|
52
|
+
ACTION_TOKEN_PURPOSES[action_name]
|
|
36
53
|
end
|
|
37
54
|
|
|
38
|
-
def
|
|
39
|
-
|
|
55
|
+
def update_password(template)
|
|
56
|
+
if user.verified_update(password_params)
|
|
57
|
+
redirect_to new_session_path, notice: t(".notice")
|
|
58
|
+
else
|
|
59
|
+
render template, status: :unprocessable_content
|
|
60
|
+
end
|
|
40
61
|
end
|
|
41
62
|
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:
|
|
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:
|
|
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
|
|
1
|
+
<h2><%= t(".title") %></h2>
|
|
2
2
|
|
|
3
3
|
<p>
|
|
4
4
|
<strong><%= current_user.email %></strong>
|
|
5
|
-
<em><%=
|
|
5
|
+
<em><%= ma_change_email_link %></em>
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
|
-
<%=
|
|
9
|
-
<%= submit_tag 'Send Verification Email' %>
|
|
10
|
-
<% end %>
|
|
8
|
+
<%= button_to t(".button"), email_verification_path %>
|
|
11
9
|
|
|
12
|
-
<p
|
|
10
|
+
<p><%= t(".message") %></p>
|
|
13
11
|
|
|
14
|
-
<%=
|
|
12
|
+
<%= ma_skip_link %>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
<h1
|
|
1
|
+
<h1><%= t(".title") %></h1>
|
|
2
2
|
|
|
3
|
-
<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 "
|
|
7
|
+
<%= form.submit t(".submit") %>
|
|
8
8
|
<% end %>
|
|
9
9
|
|
|
10
|
-
<p
|
|
10
|
+
<p><%= t(".message") %></p>
|
|
11
11
|
|
|
12
|
-
<%=
|
|
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
|
|
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) %>
|
|
@@ -2,9 +2,20 @@ 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
|
|
17
|
+
limit_creations:
|
|
18
|
+
alert: Please try again later.
|
|
8
19
|
minimalist_authentication_mailer:
|
|
9
20
|
update_password:
|
|
10
21
|
opening: Please click the link below to update your password.
|
|
@@ -26,15 +37,14 @@ en:
|
|
|
26
37
|
passwords:
|
|
27
38
|
edit:
|
|
28
39
|
instructions: Please enter your new password.
|
|
29
|
-
password:
|
|
30
|
-
placeholder: New password
|
|
31
|
-
password_confirmation:
|
|
32
|
-
placeholder: Confirm password
|
|
33
|
-
submit: Reset Password
|
|
34
40
|
title: Reset Password
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
form:
|
|
42
|
+
submit: Save Password
|
|
43
|
+
invalid_token: Your link has expired or is invalid. Please request a new one to continue.
|
|
44
|
+
new:
|
|
45
|
+
instructions: Choose a secure password to complete your account setup.
|
|
46
|
+
title: Complete Your Account Setup
|
|
47
|
+
notice: Password successfully updated
|
|
38
48
|
sessions:
|
|
39
49
|
create:
|
|
40
50
|
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
|
-
|
|
22
|
-
attr_accessor :session_key
|
|
42
|
+
attribute :session_key, default: :user_id
|
|
23
43
|
|
|
24
44
|
# The application user class name
|
|
25
|
-
|
|
26
|
-
attr_accessor :user_model_name
|
|
45
|
+
attribute :user_model_name, :string, default: "::User"
|
|
27
46
|
|
|
28
47
|
# Toggle all email validations.
|
|
29
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,19 @@ module MinimalistAuthentication
|
|
|
14
14
|
|
|
15
15
|
helper MinimalistAuthentication::ApplicationHelper
|
|
16
16
|
|
|
17
|
-
helper_method :current_user, :logged_in?, :
|
|
17
|
+
helper_method :authorized?, :current_user, :logged_in?, :login_redirect_to
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module ClassMethods
|
|
21
|
+
def limit_creations(**)
|
|
22
|
+
rate_limit(
|
|
23
|
+
to: 10,
|
|
24
|
+
within: 3.minutes,
|
|
25
|
+
only: :create,
|
|
26
|
+
with: -> { redirect_to new_session_path, alert: t("limit_creations.alert") },
|
|
27
|
+
**
|
|
28
|
+
)
|
|
29
|
+
end
|
|
18
30
|
end
|
|
19
31
|
|
|
20
32
|
# Returns true if the user is logged in
|
|
@@ -33,6 +45,11 @@ module MinimalistAuthentication
|
|
|
33
45
|
current_user.present?
|
|
34
46
|
end
|
|
35
47
|
|
|
48
|
+
# Returns the path to redirect to after login
|
|
49
|
+
def login_redirect_to
|
|
50
|
+
public_send(MinimalistAuthentication.configuration.login_redirect_path)
|
|
51
|
+
end
|
|
52
|
+
|
|
36
53
|
# Logs in a user by setting the session key and updating the Current user
|
|
37
54
|
# Should only be called after a successful authentication
|
|
38
55
|
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:
|
|
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
|
|
44
|
-
|
|
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
|
|
@@ -10,6 +10,10 @@ module MinimalistAuthentication
|
|
|
10
10
|
|
|
11
11
|
skip_before_action :authorization_required, only: %i[new create]
|
|
12
12
|
before_action :redirect_logged_in_users, only: :new
|
|
13
|
+
|
|
14
|
+
# Limit create requests by ip address and user identifier
|
|
15
|
+
limit_creations(to: 50)
|
|
16
|
+
limit_creations(by: -> { identifier&.downcase })
|
|
13
17
|
end
|
|
14
18
|
|
|
15
19
|
def new
|
|
@@ -80,11 +84,7 @@ module MinimalistAuthentication
|
|
|
80
84
|
end
|
|
81
85
|
|
|
82
86
|
def identifier
|
|
83
|
-
user_params
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def login_redirect_to
|
|
87
|
-
send(MinimalistAuthentication.configuration.login_redirect_path)
|
|
87
|
+
user_params[:email] || user_params[:username]
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
def logout_redirect_to
|
|
@@ -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
|
-
|
|
13
|
-
|
|
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
|
|
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)
|
|
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
|
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.
|
|
4
|
+
version: 3.4.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.
|
|
108
|
+
version: 3.2.0
|
|
107
109
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
110
|
requirements:
|
|
109
111
|
- - ">="
|