rails_jwt_auth 0.23.2 → 1.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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +77 -219
  3. data/app/controllers/concerns/rails_jwt_auth/authenticable_helper.rb +31 -0
  4. data/app/controllers/rails_jwt_auth/confirmations_controller.rb +3 -6
  5. data/app/controllers/rails_jwt_auth/invitations_controller.rb +5 -8
  6. data/app/controllers/rails_jwt_auth/passwords_controller.rb +3 -7
  7. data/app/controllers/rails_jwt_auth/sessions_controller.rb +13 -9
  8. data/app/mailers/rails_jwt_auth/mailer.rb +32 -47
  9. data/app/models/concerns/rails_jwt_auth/authenticatable.rb +31 -25
  10. data/app/models/concerns/rails_jwt_auth/confirmable.rb +54 -47
  11. data/app/models/concerns/rails_jwt_auth/invitable.rb +10 -11
  12. data/app/models/concerns/rails_jwt_auth/recoverable.rb +29 -28
  13. data/app/models/concerns/rails_jwt_auth/trackable.rb +1 -1
  14. data/app/views/rails_jwt_auth/mailer/confirmation_instructions.html.erb +2 -2
  15. data/app/views/rails_jwt_auth/mailer/reset_password_instructions.html.erb +2 -2
  16. data/app/views/rails_jwt_auth/mailer/send_invitation.html.erb +2 -2
  17. data/app/views/rails_jwt_auth/mailer/set_password_instructions.html.erb +2 -2
  18. data/lib/generators/rails_jwt_auth/install_generator.rb +4 -5
  19. data/lib/generators/rails_jwt_auth/migrate_generator.rb +17 -0
  20. data/lib/generators/templates/initializer.rb +15 -18
  21. data/lib/generators/templates/migration.rb +29 -0
  22. data/lib/rails_jwt_auth.rb +54 -20
  23. data/lib/rails_jwt_auth/engine.rb +0 -21
  24. data/lib/rails_jwt_auth/jwt_manager.rb +33 -0
  25. data/lib/rails_jwt_auth/spec_helpers.rb +15 -0
  26. data/lib/rails_jwt_auth/version.rb +1 -1
  27. metadata +8 -10
  28. data/app/controllers/concerns/rails_jwt_auth/warden_helper.rb +0 -29
  29. data/lib/rails_jwt_auth/jwt/manager.rb +0 -41
  30. data/lib/rails_jwt_auth/jwt/request.rb +0 -34
  31. data/lib/rails_jwt_auth/spec/helpers.rb +0 -17
  32. data/lib/rails_jwt_auth/spec/not_authorized.rb +0 -6
  33. data/lib/rails_jwt_auth/strategies/jwt.rb +0 -17
  34. data/lib/tasks/rails_token_jwt_tasks.rake +0 -4
@@ -4,20 +4,17 @@ module RailsJwtAuth
4
4
  include RenderHelper
5
5
 
6
6
  def create
7
- attr_hash = invitation_create_params
8
- user = RailsJwtAuth.model.invite!(attr_hash)
7
+ user = RailsJwtAuth.model.invite!(invitation_create_params)
9
8
  user.errors.empty? ? render_204 : render_422(user.errors.details)
10
9
  end
11
10
 
12
11
  def update
13
- attr_hash = invitation_update_params
14
- user = RailsJwtAuth.model.where(invitation_token: params[:id]).first
12
+ return render_404 unless
13
+ params[:id] &&
14
+ (user = RailsJwtAuth.model.where(invitation_token: params[:id]).first)
15
15
 
16
- return render_404 if user.blank?
17
-
18
- user.assign_attributes attr_hash
16
+ user.assign_attributes invitation_update_params
19
17
  user.accept_invitation!
20
-
21
18
  return render_204 if user.errors.empty? && user.save
22
19
 
23
20
  render_422(user.errors.details)
@@ -11,13 +11,9 @@ module RailsJwtAuth
11
11
  end
12
12
 
13
13
  def update
14
- if params[:reset_password_token].blank?
15
- return render_422(reset_password_token: [{error: :not_found}])
16
- end
17
-
18
- user = RailsJwtAuth.model.where(reset_password_token: params[:reset_password_token]).first
19
-
20
- return render_422(reset_password_token: [{error: :not_found}]) unless user
14
+ return render_404 unless
15
+ params[:id] &&
16
+ (user = RailsJwtAuth.model.where(reset_password_token: params[:id]).first)
21
17
 
22
18
  return render_422(password: [{error: :blank}]) if password_update_params[:password].blank?
23
19
 
@@ -1,36 +1,40 @@
1
- require 'rails_jwt_auth/jwt/manager'
2
- require 'rails_jwt_auth/jwt/request'
3
-
4
1
  module RailsJwtAuth
5
2
  class SessionsController < ApplicationController
6
3
  include ParamsHelper
7
4
  include RenderHelper
8
5
 
9
6
  def create
10
- user = RailsJwtAuth.model.where(RailsJwtAuth.auth_field_name =>
11
- session_create_params[RailsJwtAuth.auth_field_name].to_s.downcase).first
7
+ user = find_user
12
8
 
13
9
  if !user
14
10
  render_422 session: [{error: :invalid_session}]
15
11
  elsif user.respond_to?('confirmed?') && !user.confirmed?
16
12
  render_422 session: [{error: :unconfirmed}]
17
13
  elsif user.authenticate(session_create_params[:password])
18
- render_session get_jwt(user), user
14
+ render_session generate_jwt(user), user
19
15
  else
20
16
  render_422 session: [{error: :invalid_session}]
21
17
  end
22
18
  end
23
19
 
24
20
  def destroy
21
+ return render_404 unless RailsJwtAuth.simultaneous_sessions > 0
22
+
25
23
  authenticate!
26
- current_user.destroy_auth_token Jwt::Request.new(request).auth_token
24
+ payload = JwtManager.decode_from_request(request)&.first
25
+ current_user.destroy_auth_token payload['auth_token']
27
26
  render_204
28
27
  end
29
28
 
30
29
  private
31
30
 
32
- def get_jwt(user)
33
- RailsJwtAuth::Jwt::Manager.encode(user.to_token_payload(request))
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
34
38
  end
35
39
  end
36
40
  end
@@ -2,71 +2,56 @@ if defined?(ActionMailer)
2
2
  class RailsJwtAuth::Mailer < ApplicationMailer
3
3
  default from: RailsJwtAuth.mailer_sender
4
4
 
5
- def confirmation_instructions(id)
6
- @user = RailsJwtAuth.model.find(id)
5
+ def confirmation_instructions(user)
6
+ raise RailsJwtAuth::NotConfirmationsUrl unless RailsJwtAuth.confirmations_url.present?
7
+ @user = user
7
8
 
8
- if RailsJwtAuth.confirmation_url
9
- url, params = RailsJwtAuth.confirmation_url.split('?')
10
- params = params ? params.split('&') : []
11
- params.push("confirmation_token=#{@user.confirmation_token}")
12
-
13
- @confirmation_url = "#{url}?#{params.join('&')}"
14
- else
15
- @confirmation_url = confirmation_url(confirmation_token: @user.confirmation_token)
16
- end
9
+ url, params = RailsJwtAuth.confirmations_url.split('?')
10
+ params = params ? params.split('&') : []
11
+ params.push("confirmation_token=#{@user.confirmation_token}")
12
+ @confirmations_url = "#{url}?#{params.join('&')}"
17
13
 
18
14
  subject = I18n.t('rails_jwt_auth.mailer.confirmation_instructions.subject')
19
- mail(to: @user.unconfirmed_email || @user.email, subject: subject)
15
+ mail(to: @user.unconfirmed_email || @user[RailsJwtAuth.email_field_name], subject: subject)
20
16
  end
21
17
 
22
- def reset_password_instructions(id)
23
- @user = RailsJwtAuth.model.find(id)
24
-
25
- if RailsJwtAuth.reset_password_url
26
- url, params = RailsJwtAuth.reset_password_url.split('?')
27
- params = params ? params.split('&') : []
28
- params.push("reset_password_token=#{@user.reset_password_token}")
18
+ def reset_password_instructions(user)
19
+ raise RailsJwtAuth::NotResetPasswordsUrl unless RailsJwtAuth.reset_passwords_url.present?
20
+ @user = user
29
21
 
30
- @reset_password_url = "#{url}?#{params.join('&')}"
31
- else
32
- @reset_password_url = password_url(reset_password_token: @user.reset_password_token)
33
- end
22
+ url, params = RailsJwtAuth.reset_passwords_url.split('?')
23
+ params = params ? params.split('&') : []
24
+ params.push("reset_password_token=#{@user.reset_password_token}")
25
+ @reset_passwords_url = "#{url}?#{params.join('&')}"
34
26
 
35
27
  subject = I18n.t('rails_jwt_auth.mailer.reset_password_instructions.subject')
36
- mail(to: @user.email, subject: subject)
28
+ mail(to: @user[RailsJwtAuth.email_field_name], subject: subject)
37
29
  end
38
30
 
39
- def set_password_instructions(id)
40
- @user = RailsJwtAuth.model.find(id)
41
-
42
- if RailsJwtAuth.set_password_url
43
- url, params = RailsJwtAuth.set_password_url.split('?')
44
- params = params ? params.split('&') : []
45
- params.push("reset_password_token=#{@user.reset_password_token}")
31
+ def set_password_instructions(user)
32
+ raise RailsJwtAuth::NotSetPasswordsUrl unless RailsJwtAuth.set_passwords_url.present?
33
+ @user = user
46
34
 
47
- @reset_password_url = "#{url}?#{params.join('&')}"
48
- else
49
- @reset_password_url = password_url(reset_password_token: @user.reset_password_token)
50
- end
35
+ url, params = RailsJwtAuth.set_passwords_url.split('?')
36
+ params = params ? params.split('&') : []
37
+ params.push("reset_password_token=#{@user.reset_password_token}")
38
+ @reset_passwords_url = "#{url}?#{params.join('&')}"
51
39
 
52
40
  subject = I18n.t('rails_jwt_auth.mailer.set_password_instructions.subject')
53
- mail(to: @user.email, subject: subject)
41
+ mail(to: @user[RailsJwtAuth.email_field_name], subject: subject)
54
42
  end
55
43
 
56
- def send_invitation(id)
57
- @user = RailsJwtAuth.model.find(id)
44
+ def send_invitation(user)
45
+ raise RailsJwtAuth::NotInvitationsUrl unless RailsJwtAuth.invitations_url.present?
46
+ @user = user
58
47
 
59
- if RailsJwtAuth.accept_invitation_url
60
- url, params = RailsJwtAuth.accept_invitation_url.split '?'
61
- params = params ? params.split('&') : []
62
- params.push("invitation_token=#{@user.invitation_token}")
63
- @accept_invitation_url = "#{url}?#{params.join('&')}"
64
- else
65
- @accept_invitation_url = invitations_url(invitation_token: @user.invitation_token)
66
- end
48
+ url, params = RailsJwtAuth.invitations_url.split '?'
49
+ params = params ? params.split('&') : []
50
+ params.push("invitation_token=#{@user.invitation_token}")
51
+ @invitations_url = "#{url}?#{params.join('&')}"
67
52
 
68
53
  subject = I18n.t('rails_jwt_auth.mailer.send_invitation.subject')
69
- mail(to: @user.email, subject: subject)
54
+ mail(to: @user[RailsJwtAuth.email_field_name], subject: subject)
70
55
  end
71
56
  end
72
57
  end
@@ -2,6 +2,21 @@ include ActiveModel::SecurePassword
2
2
 
3
3
  module RailsJwtAuth
4
4
  module Authenticatable
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+
8
+ base.class_eval do
9
+ if defined?(Mongoid) && ancestors.include?(Mongoid::Document)
10
+ field :password_digest, type: String
11
+ field :auth_tokens, type: Array if RailsJwtAuth.simultaneous_sessions > 0
12
+ elsif defined?(ActiveRecord) && ancestors.include?(ActiveRecord::Base)
13
+ serialize :auth_tokens, Array
14
+ end
15
+
16
+ has_secure_password
17
+ end
18
+ end
19
+
5
20
  def regenerate_auth_token(token = nil)
6
21
  new_token = SecureRandom.base58(24)
7
22
 
@@ -35,42 +50,33 @@ module RailsJwtAuth
35
50
  errors.add(:password, 'blank')
36
51
  end
37
52
 
53
+ params.merge!(reset_password_token: nil, reset_password_sent_at: nil) if reset_password_token
54
+
38
55
  errors.empty? ? update_attributes(params) : false
39
56
  end
40
57
 
41
- def to_token_payload(_request)
42
- {auth_token: regenerate_auth_token}
58
+ def to_token_payload(_request=nil)
59
+ if RailsJwtAuth.simultaneous_sessions > 0
60
+ {auth_token: regenerate_auth_token}
61
+ else
62
+ {id: id.to_s}
63
+ end
43
64
  end
44
65
 
45
66
  module ClassMethods
46
- def get_by_token(token)
47
- if defined?(Mongoid) && ancestors.include?(Mongoid::Document)
48
- where(auth_tokens: token).first
49
- elsif defined?(ActiveRecord) && ancestors.include?(ActiveRecord::Base)
50
- where('auth_tokens like ?', "%#{token}%").first
67
+ def from_token_payload(payload)
68
+ if RailsJwtAuth.simultaneous_sessions > 0
69
+ get_by_token(payload['auth_token'])
70
+ else
71
+ where(id: payload['id']).first
51
72
  end
52
73
  end
53
- end
54
74
 
55
- def self.included(base)
56
- base.extend(ClassMethods)
57
-
58
- base.class_eval do
75
+ def get_by_token(token)
59
76
  if defined?(Mongoid) && ancestors.include?(Mongoid::Document)
60
- field RailsJwtAuth.auth_field_name, type: String
61
- field :password_digest, type: String
62
- field :auth_tokens, type: Array
77
+ where(auth_tokens: token).first
63
78
  elsif defined?(ActiveRecord) && ancestors.include?(ActiveRecord::Base)
64
- serialize :auth_tokens, Array
65
- end
66
-
67
- validates RailsJwtAuth.auth_field_name, presence: true, uniqueness: true
68
- validates RailsJwtAuth.auth_field_name, email: true if RailsJwtAuth.auth_field_email
69
-
70
- has_secure_password
71
-
72
- before_validation do
73
- self.email = email.downcase if email
79
+ where('auth_tokens like ?', "%#{token}%").first
74
80
  end
75
81
  end
76
82
  end
@@ -1,42 +1,5 @@
1
1
  module RailsJwtAuth
2
2
  module Confirmable
3
- def send_confirmation_instructions
4
- if confirmed? && !unconfirmed_email
5
- errors.add(:email, :already_confirmed)
6
- return false
7
- end
8
-
9
- self.confirmation_token = SecureRandom.base58(24)
10
- self.confirmation_sent_at = Time.now
11
- return false unless save
12
-
13
- mailer = Mailer.confirmation_instructions(id.to_s)
14
- RailsJwtAuth.deliver_later ? mailer.deliver_later : mailer.deliver
15
- true
16
- end
17
-
18
- def confirmed?
19
- confirmed_at.present?
20
- end
21
-
22
- def confirm!
23
- self.confirmed_at = Time.now.utc
24
- self.confirmation_token = nil
25
-
26
- if unconfirmed_email
27
- self.email = unconfirmed_email
28
- self.email_confirmation = unconfirmed_email if respond_to?(:email_confirmation)
29
- self.unconfirmed_email = nil
30
- end
31
-
32
- save
33
- end
34
-
35
- def skip_confirmation!
36
- self.confirmed_at = Time.now.utc
37
- self.confirmation_token = nil
38
- end
39
-
40
3
  def self.included(base)
41
4
  base.class_eval do
42
5
  if defined?(Mongoid) && ancestors.include?(Mongoid::Document)
@@ -44,7 +7,6 @@ module RailsJwtAuth
44
7
  # http://edgeguides.rubyonrails.org/active_job_basics.html#globalid
45
8
  include GlobalID::Identification if RailsJwtAuth.deliver_later
46
9
 
47
- field :email, type: String
48
10
  field :unconfirmed_email, type: String
49
11
  field :confirmation_token, type: String
50
12
  field :confirmation_sent_at, type: Time
@@ -60,29 +22,74 @@ module RailsJwtAuth
60
22
  end
61
23
 
62
24
  before_update do
63
- if email_changed? && email_was && !confirmed_at_changed? && !self['invitation_token']
64
- self.unconfirmed_email = email
65
- self.email = email_was
25
+ email_field = RailsJwtAuth.email_field_name!
26
+
27
+ if public_send("#{email_field}_changed?") &&
28
+ public_send("#{email_field}_was") &&
29
+ !confirmed_at_changed? &&
30
+ !self['invitation_token']
31
+ self.unconfirmed_email = self[email_field]
32
+ self[email_field] = public_send("#{email_field}_was")
66
33
 
67
34
  self.confirmation_token = SecureRandom.base58(24)
68
- self.confirmation_sent_at = Time.now
35
+ self.confirmation_sent_at = Time.current
69
36
 
70
- mailer = Mailer.confirmation_instructions(id.to_s)
37
+ mailer = Mailer.confirmation_instructions(self)
71
38
  RailsJwtAuth.deliver_later ? mailer.deliver_later : mailer.deliver
72
39
  end
73
40
  end
74
41
  end
75
42
  end
76
43
 
77
- private
44
+ def send_confirmation_instructions
45
+ email_field = RailsJwtAuth.email_field_name!
46
+
47
+ if confirmed? && !unconfirmed_email
48
+ errors.add(email_field, :already_confirmed)
49
+ return false
50
+ end
51
+
52
+ self.confirmation_token = SecureRandom.base58(24)
53
+ self.confirmation_sent_at = Time.current
54
+ return false unless save
55
+
56
+ mailer = Mailer.confirmation_instructions(self)
57
+ RailsJwtAuth.deliver_later ? mailer.deliver_later : mailer.deliver
58
+ true
59
+ end
60
+
61
+ def confirmed?
62
+ confirmed_at.present?
63
+ end
64
+
65
+ def confirm!
66
+ self.confirmed_at = Time.current
67
+ self.confirmation_token = nil
68
+
69
+ if unconfirmed_email
70
+ self[RailsJwtAuth.email_field_name!] = unconfirmed_email
71
+ self.email_confirmation = unconfirmed_email if respond_to?(:email_confirmation)
72
+ self.unconfirmed_email = nil
73
+ end
74
+
75
+ save
76
+ end
77
+
78
+ def skip_confirmation!
79
+ self.confirmed_at = Time.current
80
+ self.confirmation_token = nil
81
+ end
82
+
83
+ protected
78
84
 
79
85
  def validate_confirmation
80
86
  return true unless confirmed_at
87
+ email_field = RailsJwtAuth.email_field_name!
81
88
 
82
- if confirmed_at_was && !email_changed?
83
- errors.add(:email, :already_confirmed)
89
+ if confirmed_at_was && !public_send("#{email_field}_changed?")
90
+ errors.add(email_field, :already_confirmed)
84
91
  elsif confirmation_sent_at &&
85
- (confirmation_sent_at < (Time.now - RailsJwtAuth.confirmation_expiration_time))
92
+ (confirmation_sent_at < (Time.current - RailsJwtAuth.confirmation_expiration_time))
86
93
  errors.add(:confirmation_token, :expired)
87
94
  end
88
95
  end
@@ -1,7 +1,5 @@
1
1
  module RailsJwtAuth
2
2
  module Invitable
3
- extend ActiveSupport::Concern
4
-
5
3
  def self.included(base)
6
4
  base.extend ClassMethods
7
5
  base.class_eval do
@@ -31,7 +29,7 @@ module RailsJwtAuth
31
29
  # @return [user] The user created or found by email.
32
30
  def invite!(attributes={})
33
31
  attrs = ActiveSupport::HashWithIndifferentAccess.new(attributes.to_h)
34
- auth_field = RailsJwtAuth.auth_field_name
32
+ auth_field = RailsJwtAuth.auth_field_name!
35
33
  auth_attribute = attrs.delete(auth_field)
36
34
 
37
35
  raise ArgumentError unless auth_attribute
@@ -46,7 +44,7 @@ module RailsJwtAuth
46
44
 
47
45
  # Accept an invitation by clearing token and setting invitation_accepted_at
48
46
  def accept_invitation
49
- self.invitation_accepted_at = Time.now.utc
47
+ self.invitation_accepted_at = Time.current
50
48
  self.invitation_token = nil
51
49
  end
52
50
 
@@ -55,14 +53,14 @@ module RailsJwtAuth
55
53
 
56
54
  if valid_invitation?
57
55
  accept_invitation
58
- self.confirmed_at = Time.now.utc if respond_to?(:confirmed_at) && confirmed_at.nil?
56
+ self.confirmed_at = Time.current if respond_to?(:confirmed_at) && confirmed_at.nil?
59
57
  else
60
58
  errors.add(:invitation_token, :invalid)
61
59
  end
62
60
  end
63
61
 
64
62
  def invite!
65
- self.invitation_created_at = Time.now.utc if new_record?
63
+ self.invitation_created_at = Time.current if new_record?
66
64
 
67
65
  unless password || password_digest
68
66
  passw = SecureRandom.base58(16)
@@ -74,18 +72,18 @@ module RailsJwtAuth
74
72
 
75
73
  # users that are registered and were not invited are not reinvitable
76
74
  if !new_record? && !invited?
77
- errors.add(RailsJwtAuth.auth_field_name, :taken)
75
+ errors.add(RailsJwtAuth.auth_field_name!, :taken)
78
76
  end
79
77
 
80
78
  # users that have already accepted an invitation are not reinvitable
81
79
  if !new_record? && invited? && invitation_accepted_at.present?
82
- errors.add(RailsJwtAuth.auth_field_name, :taken)
80
+ errors.add(RailsJwtAuth.auth_field_name!, :taken)
83
81
  end
84
82
 
85
83
  return self unless errors.empty?
86
84
 
87
85
  generate_invitation_token if invitation_token.nil?
88
- self.invitation_sent_at = Time.now.utc
86
+ self.invitation_sent_at = Time.current
89
87
 
90
88
  send_invitation_mail if save(validate: false)
91
89
  self
@@ -114,14 +112,15 @@ module RailsJwtAuth
114
112
  end
115
113
 
116
114
  def send_invitation_mail
117
- mailer = Mailer.send_invitation(id.to_s)
115
+ RailsJwtAuth.email_field_name! # ensure email field es valid
116
+ mailer = Mailer.send_invitation(self)
118
117
  RailsJwtAuth.deliver_later ? mailer.deliver_later : mailer.deliver
119
118
  end
120
119
 
121
120
  def invitation_period_valid?
122
121
  time = invitation_sent_at || invitation_created_at
123
122
  expiration_time = RailsJwtAuth.invitation_expiration_time
124
- time && (expiration_time.to_i.zero? || time.utc >= expiration_time.ago)
123
+ time && (expiration_time.to_i.zero? || time >= expiration_time.ago)
125
124
  end
126
125
  end
127
126
  end