rails_jwt_auth 0.23.2 → 1.0.0

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