rails_jwt_auth 1.7.2 → 2.0.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 +186 -87
- data/app/controllers/concerns/rails_jwt_auth/authenticable_helper.rb +15 -7
- data/app/controllers/concerns/rails_jwt_auth/params_helper.rb +18 -4
- data/app/controllers/concerns/rails_jwt_auth/render_helper.rb +10 -2
- data/app/controllers/rails_jwt_auth/confirmations_controller.rb +48 -10
- data/app/controllers/rails_jwt_auth/invitations_controller.rb +26 -9
- data/app/controllers/rails_jwt_auth/profiles_controller.rb +50 -0
- data/app/controllers/rails_jwt_auth/reset_passwords_controller.rb +65 -0
- data/app/controllers/rails_jwt_auth/sessions_controller.rb +5 -21
- data/app/controllers/rails_jwt_auth/{unlocks_controller.rb → unlock_accounts_controller.rb} +2 -2
- data/app/mailers/rails_jwt_auth/mailer.rb +23 -28
- data/app/models/concerns/rails_jwt_auth/authenticatable.rb +59 -18
- data/app/models/concerns/rails_jwt_auth/confirmable.rb +41 -38
- data/app/models/concerns/rails_jwt_auth/invitable.rb +42 -77
- data/app/models/concerns/rails_jwt_auth/lockable.rb +28 -45
- data/app/models/concerns/rails_jwt_auth/recoverable.rb +20 -28
- data/app/models/concerns/rails_jwt_auth/trackable.rb +13 -2
- data/app/views/rails_jwt_auth/mailer/confirmation_instructions.html.erb +1 -1
- data/app/views/rails_jwt_auth/mailer/{email_changed.html.erb → email_change_requested_notification.html.erb} +0 -0
- data/app/views/rails_jwt_auth/mailer/{send_invitation.html.erb → invitation_instructions.html.erb} +1 -1
- data/app/views/rails_jwt_auth/mailer/password_changed_notification.html.erb +3 -0
- data/app/views/rails_jwt_auth/mailer/reset_password_instructions.html.erb +1 -1
- data/app/views/rails_jwt_auth/mailer/{send_unlock_instructions.html.erb → unlock_instructions.html.erb} +1 -1
- data/config/locales/en.yml +6 -6
- data/lib/generators/rails_jwt_auth/install_generator.rb +11 -3
- data/lib/generators/templates/initializer.rb +43 -29
- data/lib/generators/templates/migration.rb +2 -1
- data/lib/rails_jwt_auth.rb +44 -47
- data/lib/rails_jwt_auth/jwt_manager.rb +0 -4
- data/lib/rails_jwt_auth/session.rb +132 -0
- data/lib/rails_jwt_auth/version.rb +1 -1
- metadata +10 -8
- data/app/controllers/rails_jwt_auth/passwords_controller.rb +0 -32
- data/app/views/rails_jwt_auth/mailer/set_password_instructions.html.erb +0 -5
@@ -9,12 +9,20 @@ module RailsJwtAuth
|
|
9
9
|
render json: resource, root: true, status: 201
|
10
10
|
end
|
11
11
|
|
12
|
+
def render_profile(resource)
|
13
|
+
render json: resource, root: true, status: 200
|
14
|
+
end
|
15
|
+
|
12
16
|
def render_204
|
13
|
-
|
17
|
+
head 204
|
14
18
|
end
|
15
19
|
|
16
20
|
def render_404
|
17
|
-
|
21
|
+
head 404
|
22
|
+
end
|
23
|
+
|
24
|
+
def render_410
|
25
|
+
head 410
|
18
26
|
end
|
19
27
|
|
20
28
|
def render_422(errors)
|
@@ -3,22 +3,60 @@ module RailsJwtAuth
|
|
3
3
|
include ParamsHelper
|
4
4
|
include RenderHelper
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
before_action :set_user_from_token, only: [:show, :update]
|
7
|
+
before_action :set_user_from_email, only: [:create]
|
8
|
+
|
9
|
+
# used to verify token
|
10
|
+
def show
|
11
|
+
return render_404 unless @user
|
12
|
+
|
13
|
+
if user.confirmation_sent_at < RailsJwtAuth.confirmation_expiration_time.ago
|
14
|
+
return render_410
|
15
|
+
end
|
16
|
+
|
17
|
+
render_204
|
18
|
+
end
|
10
19
|
|
11
|
-
|
20
|
+
# used to resend confirmation
|
21
|
+
def create
|
22
|
+
unless @user
|
23
|
+
if RailsJwtAuth.avoid_email_errors
|
24
|
+
return render_204
|
25
|
+
else
|
26
|
+
return render_422(RailsJwtAuth.email_field_name => [{error: :not_found}])
|
27
|
+
end
|
28
|
+
end
|
12
29
|
|
13
|
-
user.send_confirmation_instructions ? render_204 : render_422(user.errors.details)
|
30
|
+
@user.send_confirmation_instructions ? render_204 : render_422(@user.errors.details)
|
14
31
|
end
|
15
32
|
|
33
|
+
# used to accept confirmation
|
16
34
|
def update
|
17
|
-
return render_404 unless
|
18
|
-
|
19
|
-
|
35
|
+
return render_404 unless @user
|
36
|
+
|
37
|
+
@user.confirm ? render_204 : render_422(@user.errors.details)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def set_user_from_token
|
43
|
+
return if params[:id].blank?
|
44
|
+
|
45
|
+
@user = RailsJwtAuth.model.where(confirmation_token: params[:id]).first
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def set_user_from_email
|
50
|
+
email = (confirmation_create_params[RailsJwtAuth.email_field_name] || '').strip
|
51
|
+
email.downcase! if RailsJwtAuth.downcase_auth_field
|
52
|
+
|
53
|
+
if email.blank?
|
54
|
+
return render_422(RailsJwtAuth.email_field_name => [{error: :blank}])
|
55
|
+
elsif !email.match?(RailsJwtAuth.email_regex)
|
56
|
+
return render_422(RailsJwtAuth.email_field_name => [{error: :format}])
|
57
|
+
end
|
20
58
|
|
21
|
-
user
|
59
|
+
@user = RailsJwtAuth.model.where(RailsJwtAuth.email_field_name => email).first
|
22
60
|
end
|
23
61
|
end
|
24
62
|
end
|
@@ -3,22 +3,39 @@ module RailsJwtAuth
|
|
3
3
|
include ParamsHelper
|
4
4
|
include RenderHelper
|
5
5
|
|
6
|
+
before_action :authenticate!, only: [:create]
|
7
|
+
before_action :set_user_from_token, only: [:show, :update]
|
8
|
+
|
9
|
+
# used to verify token
|
10
|
+
def show
|
11
|
+
return render_404 unless @user
|
12
|
+
|
13
|
+
@user.expired_invitation_token? ? render_410 : render_204
|
14
|
+
end
|
15
|
+
|
16
|
+
# used to invite a user, if user is invited send new invitation
|
6
17
|
def create
|
7
|
-
|
8
|
-
user = RailsJwtAuth.model.invite!(invitation_create_params)
|
18
|
+
user = RailsJwtAuth.model.invite(invitation_create_params)
|
9
19
|
user.errors.empty? ? render_204 : render_422(user.errors.details)
|
10
20
|
end
|
11
21
|
|
22
|
+
# used to accept invitation
|
12
23
|
def update
|
13
|
-
return render_404 unless
|
14
|
-
|
15
|
-
|
24
|
+
return render_404 unless @user
|
25
|
+
|
26
|
+
if @user.accept_invitation(invitation_update_params)
|
27
|
+
render_204
|
28
|
+
else
|
29
|
+
render_422(@user.errors.details)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
16
34
|
|
17
|
-
|
18
|
-
|
19
|
-
return render_204 if user.errors.empty? && user.save
|
35
|
+
def set_user_from_token
|
36
|
+
return if params[:id].blank?
|
20
37
|
|
21
|
-
|
38
|
+
@user = RailsJwtAuth.model.where(invitation_token: params[:id]).first
|
22
39
|
end
|
23
40
|
end
|
24
41
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module RailsJwtAuth
|
2
|
+
class ProfilesController < ApplicationController
|
3
|
+
include ParamsHelper
|
4
|
+
include RenderHelper
|
5
|
+
|
6
|
+
PASSWORD_PARAMS = %i[current_password password password_confirmation].freeze
|
7
|
+
|
8
|
+
before_action :authenticate!
|
9
|
+
|
10
|
+
def show
|
11
|
+
render_profile current_user
|
12
|
+
end
|
13
|
+
|
14
|
+
def update
|
15
|
+
if current_user.update(profile_update_params)
|
16
|
+
render_204
|
17
|
+
else
|
18
|
+
render_422(current_user.errors.details)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def password
|
23
|
+
if current_user.update_password(update_password_params)
|
24
|
+
render_204
|
25
|
+
else
|
26
|
+
render_422(current_user.errors.details)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def email
|
31
|
+
return update unless current_user.is_a?(RailsJwtAuth::Confirmable)
|
32
|
+
|
33
|
+
if current_user.update_email(profile_update_email_params)
|
34
|
+
render_204
|
35
|
+
else
|
36
|
+
render_422(current_user.errors.details)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def changing_password?
|
43
|
+
profile_update_params.values_at(*PASSWORD_PARAMS).any?(&:present?)
|
44
|
+
end
|
45
|
+
|
46
|
+
def update_password_params
|
47
|
+
profile_update_password_params.merge(current_auth_token: jwt_payload['auth_token'])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module RailsJwtAuth
|
2
|
+
class ResetPasswordsController < ApplicationController
|
3
|
+
include ParamsHelper
|
4
|
+
include RenderHelper
|
5
|
+
|
6
|
+
before_action :set_user_from_token, only: [:show, :update]
|
7
|
+
before_action :set_user_from_email, only: [:create]
|
8
|
+
|
9
|
+
# used to verify token
|
10
|
+
def show
|
11
|
+
return render_404 unless @user
|
12
|
+
|
13
|
+
if @user.reset_password_sent_at < RailsJwtAuth.reset_password_expiration_time.ago
|
14
|
+
return render_410
|
15
|
+
end
|
16
|
+
|
17
|
+
render_204
|
18
|
+
end
|
19
|
+
|
20
|
+
# used to request restore password
|
21
|
+
def create
|
22
|
+
unless @user
|
23
|
+
if RailsJwtAuth.avoid_email_errors
|
24
|
+
return render_204
|
25
|
+
else
|
26
|
+
return render_422(RailsJwtAuth.email_field_name => [{error: :not_found}])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
@user.send_reset_password_instructions ? render_204 : render_422(@user.errors.details)
|
31
|
+
end
|
32
|
+
|
33
|
+
# used to set new password
|
34
|
+
def update
|
35
|
+
return render_404 unless @user
|
36
|
+
|
37
|
+
if @user.set_reset_password(reset_password_update_params)
|
38
|
+
render_204
|
39
|
+
else
|
40
|
+
render_422(@user.errors.details)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def set_user_from_token
|
47
|
+
return if params[:id].blank?
|
48
|
+
|
49
|
+
@user = RailsJwtAuth.model.where(reset_password_token: params[:id]).first
|
50
|
+
end
|
51
|
+
|
52
|
+
def set_user_from_email
|
53
|
+
email = (reset_password_create_params[RailsJwtAuth.email_field_name] || '').strip
|
54
|
+
email.downcase! if RailsJwtAuth.downcase_auth_field
|
55
|
+
|
56
|
+
if email.blank?
|
57
|
+
return render_422(RailsJwtAuth.email_field_name => [{error: :blank}])
|
58
|
+
elsif !email.match?(RailsJwtAuth.email_regex)
|
59
|
+
return render_422(RailsJwtAuth.email_field_name => [{error: :format}])
|
60
|
+
end
|
61
|
+
|
62
|
+
@user = RailsJwtAuth.model.where(RailsJwtAuth.email_field_name => email).first
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -4,16 +4,12 @@ module RailsJwtAuth
|
|
4
4
|
include RenderHelper
|
5
5
|
|
6
6
|
def create
|
7
|
-
|
7
|
+
se = Session.new(session_create_params)
|
8
8
|
|
9
|
-
if !
|
10
|
-
|
11
|
-
elsif user.respond_to?('confirmed?') && !user.confirmed?
|
12
|
-
render_422 session: [{error: :unconfirmed}]
|
13
|
-
elsif user.authentication?(session_create_params[:password])
|
14
|
-
render_session generate_jwt(user), user
|
9
|
+
if se.generate!(request)
|
10
|
+
render_session se.jwt, se.user
|
15
11
|
else
|
16
|
-
render_422
|
12
|
+
render_422 se.errors.details
|
17
13
|
end
|
18
14
|
end
|
19
15
|
|
@@ -21,20 +17,8 @@ module RailsJwtAuth
|
|
21
17
|
return render_404 unless RailsJwtAuth.simultaneous_sessions > 0
|
22
18
|
|
23
19
|
authenticate!
|
24
|
-
|
25
|
-
current_user.destroy_auth_token payload['auth_token']
|
20
|
+
current_user.destroy_auth_token @jwt_payload['auth_token']
|
26
21
|
render_204
|
27
22
|
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def generate_jwt(user)
|
32
|
-
JwtManager.encode(user.to_token_payload(request))
|
33
|
-
end
|
34
|
-
|
35
|
-
def find_user
|
36
|
-
auth_field = RailsJwtAuth.auth_field_name!
|
37
|
-
RailsJwtAuth.model.where(auth_field => session_create_params[auth_field]).first
|
38
|
-
end
|
39
23
|
end
|
40
24
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module RailsJwtAuth
|
2
|
-
class
|
2
|
+
class UnlockAccountsController < ApplicationController
|
3
3
|
include ParamsHelper
|
4
4
|
include RenderHelper
|
5
5
|
|
@@ -8,7 +8,7 @@ module RailsJwtAuth
|
|
8
8
|
params[:id] &&
|
9
9
|
(user = RailsJwtAuth.model.where(unlock_token: params[:id]).first)
|
10
10
|
|
11
|
-
user.unlock_access
|
11
|
+
user.unlock_access ? render_204 : render_422(user.errors.details)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -4,65 +4,60 @@ if defined?(ActionMailer)
|
|
4
4
|
|
5
5
|
before_action do
|
6
6
|
@user = RailsJwtAuth.model.find(params[:user_id])
|
7
|
+
@to = @user[RailsJwtAuth.email_field_name]
|
7
8
|
@subject = I18n.t("rails_jwt_auth.mailer.#{action_name}.subject")
|
8
9
|
end
|
9
10
|
|
10
11
|
def confirmation_instructions
|
11
|
-
raise RailsJwtAuth::NotConfirmationsUrl unless RailsJwtAuth.
|
12
|
+
raise RailsJwtAuth::NotConfirmationsUrl unless RailsJwtAuth.confirm_email_url.present?
|
12
13
|
|
13
|
-
@
|
14
|
-
RailsJwtAuth.
|
14
|
+
@confirm_email_url = add_param_to_url(
|
15
|
+
RailsJwtAuth.confirm_email_url,
|
15
16
|
'confirmation_token',
|
16
17
|
@user.confirmation_token
|
17
18
|
)
|
18
19
|
|
19
|
-
mail(to: @user.unconfirmed_email || @
|
20
|
+
mail(to: @user.unconfirmed_email || @to, subject: @subject)
|
20
21
|
end
|
21
22
|
|
22
|
-
def
|
23
|
-
mail(to: @
|
23
|
+
def email_change_requested_notification
|
24
|
+
mail(to: @to, subject: @subject)
|
24
25
|
end
|
25
26
|
|
26
27
|
def reset_password_instructions
|
27
|
-
raise RailsJwtAuth::NotResetPasswordsUrl unless RailsJwtAuth.
|
28
|
+
raise RailsJwtAuth::NotResetPasswordsUrl unless RailsJwtAuth.reset_password_url.present?
|
28
29
|
|
29
|
-
@
|
30
|
-
RailsJwtAuth.
|
30
|
+
@reset_password_url = add_param_to_url(
|
31
|
+
RailsJwtAuth.reset_password_url,
|
31
32
|
'reset_password_token',
|
32
33
|
@user.reset_password_token
|
33
34
|
)
|
34
35
|
|
35
|
-
mail(to: @
|
36
|
+
mail(to: @to, subject: @subject)
|
36
37
|
end
|
37
38
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
@reset_passwords_url = add_param_to_url(
|
42
|
-
RailsJwtAuth.set_passwords_url,
|
43
|
-
'reset_password_token',
|
44
|
-
@user.reset_password_token
|
45
|
-
)
|
46
|
-
|
47
|
-
mail(to: @user[RailsJwtAuth.email_field_name], subject: @subject)
|
39
|
+
def password_changed_notification
|
40
|
+
mail(to: @to, subject: @subject)
|
48
41
|
end
|
49
42
|
|
50
|
-
def
|
51
|
-
raise RailsJwtAuth::NotInvitationsUrl unless RailsJwtAuth.
|
43
|
+
def invitation_instructions
|
44
|
+
raise RailsJwtAuth::NotInvitationsUrl unless RailsJwtAuth.accept_invitation_url.present?
|
52
45
|
|
53
|
-
@
|
54
|
-
RailsJwtAuth.
|
46
|
+
@accept_invitation_url = add_param_to_url(
|
47
|
+
RailsJwtAuth.accept_invitation_url,
|
55
48
|
'invitation_token',
|
56
49
|
@user.invitation_token
|
57
50
|
)
|
58
51
|
|
59
|
-
mail(to: @
|
52
|
+
mail(to: @to, subject: @subject)
|
60
53
|
end
|
61
54
|
|
62
|
-
def
|
63
|
-
|
55
|
+
def unlock_instructions
|
56
|
+
raise RailsJwtAuth::NotUnlockUrl unless RailsJwtAuth.unlock_account_url.present?
|
57
|
+
|
58
|
+
@unlock_account_url = add_param_to_url(RailsJwtAuth.unlock_account_url, 'unlock_token', @user.unlock_token)
|
64
59
|
|
65
|
-
mail(to: @
|
60
|
+
mail(to: @to, subject: @subject)
|
66
61
|
end
|
67
62
|
|
68
63
|
protected
|
@@ -14,22 +14,35 @@ module RailsJwtAuth
|
|
14
14
|
end
|
15
15
|
|
16
16
|
has_secure_password
|
17
|
+
|
18
|
+
before_validation do
|
19
|
+
if RailsJwtAuth.downcase_auth_field &&
|
20
|
+
public_send("#{RailsJwtAuth.auth_field_name}_changed?")
|
21
|
+
self[RailsJwtAuth.auth_field_name]&.downcase!
|
22
|
+
end
|
23
|
+
end
|
17
24
|
end
|
18
25
|
end
|
19
26
|
|
20
|
-
def
|
27
|
+
def load_auth_token
|
21
28
|
new_token = SecureRandom.base58(24)
|
22
29
|
|
23
30
|
if RailsJwtAuth.simultaneous_sessions > 1
|
24
|
-
tokens = (
|
25
|
-
|
31
|
+
tokens = (auth_tokens || []).last(RailsJwtAuth.simultaneous_sessions - 1)
|
32
|
+
self.auth_tokens = (tokens + [new_token]).uniq
|
26
33
|
else
|
27
|
-
|
34
|
+
self.auth_tokens = [new_token]
|
28
35
|
end
|
29
36
|
|
30
37
|
new_token
|
31
38
|
end
|
32
39
|
|
40
|
+
def regenerate_auth_token(token=nil)
|
41
|
+
self.auth_tokens -= [token] if token
|
42
|
+
token = load_auth_token
|
43
|
+
save ? token : false
|
44
|
+
end
|
45
|
+
|
33
46
|
def destroy_auth_token(token)
|
34
47
|
if RailsJwtAuth.simultaneous_sessions > 1
|
35
48
|
tokens = auth_tokens || []
|
@@ -39,7 +52,34 @@ module RailsJwtAuth
|
|
39
52
|
end
|
40
53
|
end
|
41
54
|
|
42
|
-
def
|
55
|
+
def to_token_payload(_request=nil)
|
56
|
+
if RailsJwtAuth.simultaneous_sessions > 0
|
57
|
+
{auth_token: auth_tokens.last}
|
58
|
+
else
|
59
|
+
{id: id.to_s}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def save_without_password
|
64
|
+
# when set password to nil only password_digest is setted to nil
|
65
|
+
# https://github.com/rails/rails/blob/master/activemodel/lib/active_model/secure_password.rb#L97
|
66
|
+
instance_variable_set("@password", nil)
|
67
|
+
self.password_confirmation = nil
|
68
|
+
self.password_digest = nil
|
69
|
+
|
70
|
+
return false unless valid_without_password?
|
71
|
+
|
72
|
+
save(validate: false)
|
73
|
+
end
|
74
|
+
|
75
|
+
def valid_without_password?
|
76
|
+
valid?
|
77
|
+
errors.delete(:password) # allow register without pass
|
78
|
+
errors.delete(:password_confirmation)
|
79
|
+
errors.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
def update_password(params)
|
43
83
|
current_password_error = if (current_password = params.delete(:current_password)).blank?
|
44
84
|
'blank'
|
45
85
|
elsif !authenticate(current_password)
|
@@ -51,28 +91,29 @@ module RailsJwtAuth
|
|
51
91
|
self.reset_password_token = self.reset_password_sent_at = nil
|
52
92
|
end
|
53
93
|
|
94
|
+
# close all sessions or other sessions when pass current_auth_token
|
95
|
+
current_auth_token = params.delete :current_auth_token
|
96
|
+
self.auth_tokens = current_auth_token ? [current_auth_token] : []
|
97
|
+
|
54
98
|
assign_attributes(params)
|
55
99
|
valid? # validates first other fields
|
56
100
|
errors.add(:current_password, current_password_error) if current_password_error
|
57
101
|
errors.add(:password, 'blank') if params[:password].blank?
|
58
102
|
|
59
|
-
errors.empty?
|
60
|
-
|
103
|
+
return false unless errors.empty?
|
104
|
+
return false unless save
|
61
105
|
|
62
|
-
|
63
|
-
if RailsJwtAuth.simultaneous_sessions > 0
|
64
|
-
{auth_token: regenerate_auth_token}
|
65
|
-
else
|
66
|
-
{id: id.to_s}
|
67
|
-
end
|
68
|
-
end
|
106
|
+
deliver_password_changed_notification
|
69
107
|
|
70
|
-
|
71
|
-
authenticate(pass)
|
108
|
+
true
|
72
109
|
end
|
73
110
|
|
74
|
-
|
75
|
-
|
111
|
+
protected
|
112
|
+
|
113
|
+
def deliver_password_changed_notification
|
114
|
+
return unless RailsJwtAuth.send_password_changed_notification
|
115
|
+
|
116
|
+
RailsJwtAuth.send_email(:password_changed_notification, self)
|
76
117
|
end
|
77
118
|
|
78
119
|
module ClassMethods
|