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