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
@@ -1,20 +1,42 @@
1
1
  module RailsJwtAuth
2
2
  module Recoverable
3
+ def self.included(base)
4
+ base.class_eval do
5
+ if defined?(Mongoid) && base.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 :reset_password_token, type: String
11
+ field :reset_password_sent_at, type: Time
12
+ end
13
+
14
+ validate :validate_reset_password_token, if: :password_digest_changed?
15
+
16
+ before_update do
17
+ self.reset_password_token = nil if password_digest_changed? && reset_password_token
18
+ end
19
+ end
20
+ end
21
+
3
22
  def send_reset_password_instructions
23
+ email_field = RailsJwtAuth.email_field_name! # ensure email field es valid
24
+
4
25
  if self.class.ancestors.include?(RailsJwtAuth::Confirmable) && !confirmed?
5
- errors.add(:email, :unconfirmed)
26
+ errors.add(email_field, :unconfirmed)
6
27
  return false
7
28
  end
8
29
 
9
30
  self.reset_password_token = SecureRandom.base58(24)
10
- self.reset_password_sent_at = Time.now
31
+ self.reset_password_sent_at = Time.current
11
32
  return false unless save
12
33
 
13
- mailer = Mailer.reset_password_instructions(id.to_s)
34
+ mailer = Mailer.reset_password_instructions(self)
14
35
  RailsJwtAuth.deliver_later ? mailer.deliver_later : mailer.deliver
15
36
  end
16
37
 
17
38
  def set_and_send_password_instructions
39
+ RailsJwtAuth.email_field_name! # ensure email field es valid
18
40
  return if password.present?
19
41
 
20
42
  self.password = SecureRandom.base58(48)
@@ -22,40 +44,19 @@ module RailsJwtAuth
22
44
  self.skip_confirmation! if self.class.ancestors.include?(RailsJwtAuth::Confirmable)
23
45
 
24
46
  self.reset_password_token = SecureRandom.base58(24)
25
- self.reset_password_sent_at = Time.now
47
+ self.reset_password_sent_at = Time.current
26
48
  return false unless save
27
49
 
28
- mailer = Mailer.set_password_instructions(id.to_s)
50
+ mailer = Mailer.set_password_instructions(self)
29
51
  RailsJwtAuth.deliver_later ? mailer.deliver_later : mailer.deliver
30
52
  true
31
53
  end
32
54
 
33
- def self.included(base)
34
- base.class_eval do
35
- if defined?(Mongoid) && base.ancestors.include?(Mongoid::Document)
36
- # include GlobalID::Identification to use deliver_later method
37
- # http://edgeguides.rubyonrails.org/active_job_basics.html#globalid
38
- include GlobalID::Identification if RailsJwtAuth.deliver_later
39
-
40
- field :reset_password_token, type: String
41
- field :reset_password_sent_at, type: Time
42
- end
43
-
44
- validate :validate_reset_password_token, if: :password_digest_changed?
45
-
46
- before_update do
47
- if password_digest_changed? && reset_password_token
48
- self.reset_password_token = nil
49
- end
50
- end
51
- end
52
- end
53
-
54
- private
55
+ protected
55
56
 
56
57
  def validate_reset_password_token
57
58
  if reset_password_sent_at &&
58
- (reset_password_sent_at < (Time.now - RailsJwtAuth.reset_password_expiration_time))
59
+ (reset_password_sent_at < (Time.current - RailsJwtAuth.reset_password_expiration_time))
59
60
  errors.add(:reset_password_token, :expired)
60
61
  end
61
62
  end
@@ -1,7 +1,7 @@
1
1
  module RailsJwtAuth
2
2
  module Trackable
3
3
  def update_tracked_fields!(request)
4
- self.last_sign_in_at = Time.now.utc
4
+ self.last_sign_in_at = Time.current
5
5
  self.last_sign_in_ip = request.respond_to?(:remote_ip) ? request.remote_ip : request.ip
6
6
  save(validate: false)
7
7
  end
@@ -1,5 +1,5 @@
1
- <p>Welcome <%= @user.email %>!</p>
1
+ <p>Welcome <%= @user[RailsJwtAuth.email_field_name] %>!</p>
2
2
 
3
3
  <p>You can confirm your account email through the link below:</p>
4
4
 
5
- <p><%= link_to 'Confirm my account', @confirmation_url.html_safe %></p>
5
+ <p><%= link_to 'Confirm my account', @confirmations_url.html_safe %></p>
@@ -1,8 +1,8 @@
1
- <p>Hello <%= @user.email %>!</p>
1
+ <p>Hello <%= @user[RailsJwtAuth.email_field_name] %>!</p>
2
2
 
3
3
  <p>Someone has requested a link to change your password. You can do this through the link below.</p>
4
4
 
5
- <p><%= link_to 'Change my password', @reset_password_url.html_safe %></p>
5
+ <p><%= link_to 'Change my password', @reset_passwords_url.html_safe %></p>
6
6
 
7
7
  <p>If you didn't request this, please ignore this email.</p>
8
8
  <p>Your password won't change until you access the link above and create a new one.</p>
@@ -1,6 +1,6 @@
1
- <p>Hello <%= @user.email %>!</p>
1
+ <p>Hello <%= @user[RailsJwtAuth.email_field_name] %>!</p>
2
2
 
3
3
  <p>Someone has sent you an invitation to App.</p>
4
4
  <p>To complete registration setting a password, please click the following link.</p>
5
5
 
6
- <p><%= link_to "Accept invitation", @accept_invitation_url.html_safe %></p>
6
+ <p><%= link_to "Accept invitation", @invitations_url.html_safe %></p>
@@ -1,5 +1,5 @@
1
- <p>Hello <%= @user.email %>!</p>
1
+ <p>Hello <%= @user[RailsJwtAuth.email_field_name] %>!</p>
2
2
 
3
3
  <p>You need to define your password to complete registration. You can do this through the link below.</p>
4
4
 
5
- <p><%= link_to 'Set my password', @reset_password_url.html_safe %></p>
5
+ <p><%= link_to 'Set my password', @reset_passwords_url.html_safe %></p>
@@ -6,12 +6,11 @@ class RailsJwtAuth::InstallGenerator < Rails::Generators::Base
6
6
  end
7
7
 
8
8
  def create_routes
9
- route "resource :session, controller: 'rails_jwt_auth/sessions', only: [:create, :destroy]"
10
- route "resource :registration, controller: 'rails_jwt_auth/registrations', only: [:create, :update, :destroy]"
11
-
12
- route "resource :confirmation, controller: 'rails_jwt_auth/confirmations', only: [:create, :update]"
13
- route "resource :password, controller: 'rails_jwt_auth/passwords', only: [:create, :update]"
9
+ route "resources :session, controller: 'rails_jwt_auth/sessions', only: [:create, :destroy]"
10
+ route "resources :registration, controller: 'rails_jwt_auth/registrations', only: [:create, :update, :destroy]"
14
11
 
12
+ route "resources :confirmations, controller: 'rails_jwt_auth/confirmations', only: [:create, :update]"
13
+ route "resources :passwords, controller: 'rails_jwt_auth/passwords', only: [:create, :update]"
15
14
  route "resources :invitations, controller: 'rails_jwt_auth/invitations', only: [:create, :update]"
16
15
  end
17
16
  end
@@ -0,0 +1,17 @@
1
+ class RailsJwtAuth::MigrateGenerator < Rails::Generators::Base
2
+ include Rails::Generators::Migration
3
+
4
+ source_root File.expand_path('../templates', __dir__)
5
+
6
+ def self.next_migration_number(_dir)
7
+ Time.current.strftime('%Y%m%d%H%M%S')
8
+ end
9
+
10
+ def create_initializer_file
11
+ migration_template 'migration.rb', "db/migrate/create_#{RailsJwtAuth.table_name}.rb"
12
+ end
13
+
14
+ def migration_version
15
+ "[#{Rails.version.split('.')[0..1].join('.')}]"
16
+ end
17
+ end
@@ -5,11 +5,8 @@ RailsJwtAuth.setup do |config|
5
5
  # field name used to authentication with password
6
6
  #config.auth_field_name = 'email'
7
7
 
8
- # set to true to validate auth_field email format
9
- #config.auth_field_email = true
10
-
11
- # regex used to Validate email format
12
- #config.email_regex = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
8
+ # define email field name used to send emails
9
+ #config.email_field_name = 'email'
13
10
 
14
11
  # expiration time for generated tokens
15
12
  #config.jwt_expiration_time = 7.days
@@ -23,28 +20,28 @@ RailsJwtAuth.setup do |config|
23
20
  # mailer sender
24
21
  #config.mailer_sender = 'initialize-mailer_sender@example.com'
25
22
 
26
- # url used to create email link with confirmation token
27
- #config.confirmation_url = 'http://frontend.com/confirmation'
28
-
29
23
  # expiration time for confirmation tokens
30
24
  #config.confirmation_expiration_time = 1.day
31
25
 
26
+ # expiration time for reset password tokens
27
+ #config.reset_password_expiration_time = 1.day
28
+
29
+ # time an invitation is valid after sent
30
+ # config.invitation_expiration_time = 2.days
31
+
32
+ # url used to create email link with confirmation token
33
+ #config.confirmations_url = 'http://frontend.com/confirmation'
34
+
32
35
  # url used to create email link with reset password token
33
- #config.reset_password_url = 'http://frontend.com/reset_password'
36
+ #config.reset_passwords_url = 'http://frontend.com/reset_password'
34
37
 
35
38
  # url used to create email link with set password token
36
39
  # by set_and_send_password_instructions method
37
- #config.set_password_url = 'http://frontend.com/set_password'
40
+ #config.set_passwords_url = 'http://frontend.com/set_password'
38
41
 
39
- # expiration time for reset password tokens
40
- #config.reset_password_expiration_time = 1.day
42
+ # url used to create email link with activation token parameter to accept invitation
43
+ #config.invitations_url = 'http://frontend.com/accept_invitation'
41
44
 
42
45
  # uses deliver_later to send emails instead of deliver method
43
46
  #config.deliver_later = false
44
-
45
- # time an invitation is valid after sent
46
- # config.invitation_expiration_time = 2.days
47
-
48
- # url used to create email link with activation token parameter to accept invitation
49
- # config.accept_invitation_url = 'http://frontend.com/accept_invitation'
50
47
  end
@@ -0,0 +1,29 @@
1
+ class Create<%= RailsJwtAuth.model_name.pluralize %> < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ create_table :<%= RailsJwtAuth.table_name %> do |t|
4
+ t.string :email
5
+ t.string :password_digest
6
+ t.string :auth_tokens
7
+
8
+ ## Confirmable
9
+ # t.string :unconfirmed_email
10
+ # t.string :confirmation_token
11
+ # t.datetime :confirmation_sent_at
12
+ # t.datetime :confirmed_at
13
+
14
+ ## Recoverable
15
+ # t.string :reset_password_token
16
+ # t.datetime :reset_password_sent_at
17
+
18
+ ## Trackable
19
+ # t.string :last_sign_in_ip
20
+ # t.datetime :last_sign_in_at
21
+
22
+ ## Invitable
23
+ # t.string :invitation_token
24
+ # t.datetime :invitation_sent_at
25
+ # t.datetime :invitation_accepted_at
26
+ # t.datetime :invitation_created_at
27
+ end
28
+ end
29
+ end
@@ -1,20 +1,24 @@
1
- require 'warden'
2
1
  require 'bcrypt'
3
2
 
4
3
  require 'rails_jwt_auth/engine'
4
+ require 'rails_jwt_auth/jwt_manager'
5
5
 
6
6
  module RailsJwtAuth
7
+ InvalidEmailField = Class.new(StandardError)
8
+ InvalidAuthField = Class.new(StandardError)
9
+ NotConfirmationsUrl = Class.new(StandardError)
10
+ NotInvitationsUrl = Class.new(StandardError)
11
+ NotResetPasswordsUrl = Class.new(StandardError)
12
+ NotSetPasswordsUrl = Class.new(StandardError)
13
+
7
14
  mattr_accessor :model_name
8
15
  self.model_name = 'User'
9
16
 
10
17
  mattr_accessor :auth_field_name
11
18
  self.auth_field_name = 'email'
12
19
 
13
- mattr_accessor :auth_field_email
14
- self.auth_field_email = true
15
-
16
- mattr_accessor :email_regex
17
- self.email_regex = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
20
+ mattr_accessor :email_field_name
21
+ self.email_field_name = 'email'
18
22
 
19
23
  mattr_accessor :jwt_expiration_time
20
24
  self.jwt_expiration_time = 7.days
@@ -28,35 +32,65 @@ module RailsJwtAuth
28
32
  mattr_accessor :mailer_sender
29
33
  self.mailer_sender = 'initialize-mailer_sender@example.com'
30
34
 
31
- mattr_accessor :confirmation_url
32
- self.confirmation_url = nil
33
-
34
35
  mattr_accessor :confirmation_expiration_time
35
36
  self.confirmation_expiration_time = 1.day
36
37
 
37
- mattr_accessor :reset_password_url
38
- self.reset_password_url = nil
39
-
40
- mattr_accessor :set_password_url
41
- self.set_password_url = nil
42
-
43
38
  mattr_accessor :reset_password_expiration_time
44
39
  self.reset_password_expiration_time = 1.day
45
40
 
46
- mattr_accessor :deliver_later
47
- self.deliver_later = false
48
-
49
41
  mattr_accessor :invitation_expiration_time
50
42
  self.invitation_expiration_time = 2.days
51
43
 
52
- mattr_accessor :accept_invitation_url
53
- self.accept_invitation_url = nil
44
+ mattr_accessor :confirmations_url
45
+ self.confirmations_url = nil
46
+
47
+ mattr_accessor :reset_passwords_url
48
+ self.reset_passwords_url = nil
49
+
50
+ mattr_accessor :set_passwords_url
51
+ self.set_passwords_url = nil
52
+
53
+ mattr_accessor :invitations_url
54
+ self.invitations_url = nil
55
+
56
+ mattr_accessor :deliver_later
57
+ self.deliver_later = false
54
58
 
55
59
  def self.model
56
60
  model_name.constantize
57
61
  end
58
62
 
63
+ def self.table_name
64
+ model_name.underscore.pluralize
65
+ end
66
+
59
67
  def self.setup
60
68
  yield self
61
69
  end
70
+
71
+ def self.auth_field_name!
72
+ field_name = RailsJwtAuth.auth_field_name
73
+ klass = RailsJwtAuth.model
74
+
75
+ unless field_name.present? &&
76
+ (klass.respond_to?(:column_names) && klass.column_names.include?(field_name) ||
77
+ klass.respond_to?(:fields) && klass.fields[field_name])
78
+ raise RailsJwtAuth::InvalidAuthField
79
+ end
80
+
81
+ field_name
82
+ end
83
+
84
+ def self.email_field_name!
85
+ field_name = RailsJwtAuth.email_field_name
86
+ klass = RailsJwtAuth.model
87
+
88
+ unless field_name.present? &&
89
+ (klass.respond_to?(:column_names) && klass.column_names.include?(field_name) ||
90
+ klass.respond_to?(:fields) && klass.fields[field_name])
91
+ raise RailsJwtAuth::InvalidEmailField
92
+ end
93
+
94
+ field_name
95
+ end
62
96
  end
@@ -1,25 +1,4 @@
1
1
  module RailsJwtAuth
2
2
  class Engine < ::Rails::Engine
3
- require 'rails_jwt_auth/strategies/jwt'
4
-
5
- config.generators do |g|
6
- g.test_framework :rspec
7
- g.fixture_replacement :factory_girl, dir: 'spec/factories'
8
- end
9
-
10
- initializer 'rails_jwt_auth.warden' do |app|
11
- app.middleware.insert_after ActionDispatch::Callbacks, Warden::Manager do |manager|
12
- manager.default_strategies :authentication_token
13
- manager.failure_app = UnauthorizedController
14
- end
15
-
16
- Warden::Strategies.add(:authentication_token, Strategies::Jwt)
17
-
18
- Warden::Manager.after_set_user except: :fetch do |record, warden, options|
19
- if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope])
20
- record.update_tracked_fields!(warden.request)
21
- end
22
- end
23
- end
24
3
  end
25
4
  end
@@ -0,0 +1,33 @@
1
+ require 'jwt'
2
+
3
+ module RailsJwtAuth
4
+ module JwtManager
5
+ def self.secret_key_base
6
+ Rails.application.secrets.secret_key_base || Rails.application.credentials.secret_key_base
7
+ end
8
+
9
+ # Encodes and signs JWT Payload with expiration
10
+ def self.encode(payload)
11
+ payload.reverse_merge!(meta)
12
+ JWT.encode(payload, secret_key_base)
13
+ end
14
+
15
+ # Decodes the JWT with the signed secret
16
+ # [{"auth_token"=>"xxx", "exp"=>148..., "iss"=>"RJA"}, {"typ"=>"JWT", "alg"=>"HS256"}]
17
+ def self.decode(token)
18
+ JWT.decode(token, secret_key_base)
19
+ end
20
+
21
+ # Default options to be encoded in the token
22
+ def self.meta
23
+ {
24
+ exp: RailsJwtAuth.jwt_expiration_time.from_now.to_i,
25
+ iss: RailsJwtAuth.jwt_issuer
26
+ }
27
+ end
28
+
29
+ def self.decode_from_request(request)
30
+ decode(request.env['HTTP_AUTHORIZATION']&.split&.last)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ module RailsJwtAuth
2
+ module SpecHelpers
3
+ def sign_out
4
+ warn '[DEPRECATION] `sign_out` is deprecated and not needed. Please remove it.'
5
+ end
6
+
7
+ def sign_in(user)
8
+ allow_any_instance_of(RailsJwtAuth::AuthenticableHelper)
9
+ .to receive(:authenticate!).and_return(true)
10
+
11
+ allow_any_instance_of(RailsJwtAuth::AuthenticableHelper)
12
+ .to receive(:current_user).and_return(user)
13
+ end
14
+ end
15
+ end