sorcery 0.11.0 → 0.16.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +5 -5
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/ISSUE_TEMPLATE.md +20 -0
  4. data/.github/PULL_REQUEST_TEMPLATE.md +5 -0
  5. data/.github/workflows/ruby.yml +49 -0
  6. data/.rubocop.yml +55 -0
  7. data/.rubocop_todo.yml +163 -0
  8. data/CHANGELOG.md +84 -0
  9. data/CODE_OF_CONDUCT.md +14 -0
  10. data/Gemfile +2 -2
  11. data/{LICENSE.txt → LICENSE.md} +1 -1
  12. data/README.md +34 -8
  13. data/Rakefile +3 -1
  14. data/SECURITY.md +19 -0
  15. data/gemfiles/rails_52.gemfile +7 -0
  16. data/gemfiles/rails_60.gemfile +7 -0
  17. data/lib/generators/sorcery/USAGE +1 -1
  18. data/lib/generators/sorcery/helpers.rb +4 -0
  19. data/lib/generators/sorcery/install_generator.rb +21 -21
  20. data/lib/generators/sorcery/templates/initializer.rb +176 -69
  21. data/lib/generators/sorcery/templates/migration/activity_logging.rb +5 -5
  22. data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +4 -4
  23. data/lib/generators/sorcery/templates/migration/core.rb +4 -4
  24. data/lib/generators/sorcery/templates/migration/external.rb +3 -3
  25. data/lib/generators/sorcery/templates/migration/magic_login.rb +9 -0
  26. data/lib/generators/sorcery/templates/migration/remember_me.rb +3 -3
  27. data/lib/generators/sorcery/templates/migration/reset_password.rb +5 -4
  28. data/lib/generators/sorcery/templates/migration/user_activation.rb +4 -4
  29. data/lib/sorcery.rb +2 -0
  30. data/lib/sorcery/adapters/active_record_adapter.rb +4 -3
  31. data/lib/sorcery/adapters/mongoid_adapter.rb +23 -11
  32. data/lib/sorcery/controller.rb +26 -15
  33. data/lib/sorcery/controller/config.rb +7 -5
  34. data/lib/sorcery/controller/submodules/activity_logging.rb +9 -3
  35. data/lib/sorcery/controller/submodules/external.rb +49 -33
  36. data/lib/sorcery/controller/submodules/http_basic_auth.rb +2 -0
  37. data/lib/sorcery/controller/submodules/remember_me.rb +3 -8
  38. data/lib/sorcery/controller/submodules/session_timeout.rb +28 -5
  39. data/lib/sorcery/crypto_providers/aes256.rb +2 -1
  40. data/lib/sorcery/crypto_providers/bcrypt.rb +8 -2
  41. data/lib/sorcery/engine.rb +16 -3
  42. data/lib/sorcery/model.rb +14 -10
  43. data/lib/sorcery/model/config.rb +12 -4
  44. data/lib/sorcery/model/submodules/brute_force_protection.rb +6 -7
  45. data/lib/sorcery/model/submodules/external.rb +19 -3
  46. data/lib/sorcery/model/submodules/magic_login.rb +130 -0
  47. data/lib/sorcery/model/submodules/reset_password.rb +25 -2
  48. data/lib/sorcery/model/submodules/user_activation.rb +1 -1
  49. data/lib/sorcery/model/temporary_token.rb +3 -1
  50. data/lib/sorcery/protocols/oauth.rb +1 -0
  51. data/lib/sorcery/providers/auth0.rb +46 -0
  52. data/lib/sorcery/providers/battlenet.rb +51 -0
  53. data/lib/sorcery/providers/discord.rb +52 -0
  54. data/lib/sorcery/providers/heroku.rb +1 -0
  55. data/lib/sorcery/providers/instagram.rb +73 -0
  56. data/lib/sorcery/providers/line.rb +63 -0
  57. data/lib/sorcery/providers/linkedin.rb +45 -36
  58. data/lib/sorcery/providers/vk.rb +5 -4
  59. data/lib/sorcery/providers/wechat.rb +8 -6
  60. data/lib/sorcery/test_helpers/internal.rb +5 -4
  61. data/lib/sorcery/test_helpers/internal/rails.rb +11 -11
  62. data/lib/sorcery/test_helpers/rails/request.rb +20 -0
  63. data/lib/sorcery/version.rb +1 -1
  64. data/sorcery.gemspec +27 -11
  65. data/spec/active_record/user_activation_spec.rb +2 -2
  66. data/spec/active_record/user_activity_logging_spec.rb +2 -2
  67. data/spec/active_record/user_brute_force_protection_spec.rb +2 -2
  68. data/spec/active_record/user_magic_login_spec.rb +15 -0
  69. data/spec/active_record/user_oauth_spec.rb +2 -2
  70. data/spec/active_record/user_remember_me_spec.rb +2 -2
  71. data/spec/active_record/user_reset_password_spec.rb +2 -2
  72. data/spec/active_record/user_spec.rb +0 -10
  73. data/spec/controllers/controller_http_basic_auth_spec.rb +1 -1
  74. data/spec/controllers/controller_oauth2_spec.rb +230 -123
  75. data/spec/controllers/controller_oauth_spec.rb +13 -7
  76. data/spec/controllers/controller_remember_me_spec.rb +16 -8
  77. data/spec/controllers/controller_session_timeout_spec.rb +90 -3
  78. data/spec/controllers/controller_spec.rb +13 -3
  79. data/spec/orm/active_record.rb +2 -2
  80. data/spec/providers/example_provider_spec.rb +17 -0
  81. data/spec/providers/example_spec.rb +17 -0
  82. data/spec/providers/vk_spec.rb +42 -0
  83. data/spec/rails_app/app/assets/config/manifest.js +1 -0
  84. data/spec/rails_app/app/controllers/application_controller.rb +2 -0
  85. data/spec/rails_app/app/controllers/sorcery_controller.rb +152 -33
  86. data/spec/rails_app/app/mailers/sorcery_mailer.rb +7 -0
  87. data/spec/rails_app/app/views/sorcery_mailer/magic_login_email.html.erb +13 -0
  88. data/spec/rails_app/app/views/sorcery_mailer/magic_login_email.text.erb +6 -0
  89. data/spec/rails_app/config/application.rb +8 -3
  90. data/spec/rails_app/config/boot.rb +1 -1
  91. data/spec/rails_app/config/environment.rb +1 -1
  92. data/spec/rails_app/config/routes.rb +17 -0
  93. data/spec/rails_app/config/secrets.yml +4 -0
  94. data/spec/rails_app/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +2 -2
  95. data/spec/rails_app/db/migrate/invalidate_active_sessions/20180221093235_add_invalidate_active_sessions_before_to_users.rb +9 -0
  96. data/spec/rails_app/db/migrate/magic_login/20170924151831_add_magic_login_to_users.rb +17 -0
  97. data/spec/rails_app/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +2 -0
  98. data/spec/rails_app/db/schema.rb +7 -9
  99. data/spec/shared_examples/user_magic_login_shared_examples.rb +150 -0
  100. data/spec/shared_examples/user_oauth_shared_examples.rb +1 -1
  101. data/spec/shared_examples/user_remember_me_shared_examples.rb +1 -1
  102. data/spec/shared_examples/user_reset_password_shared_examples.rb +37 -5
  103. data/spec/shared_examples/user_shared_examples.rb +104 -43
  104. data/spec/sorcery_crypto_providers_spec.rb +61 -1
  105. data/spec/sorcery_temporary_token_spec.rb +27 -0
  106. data/spec/spec.opts +1 -1
  107. data/spec/spec_helper.rb +2 -2
  108. data/spec/support/migration_helper.rb +29 -0
  109. data/spec/support/providers/example.rb +11 -0
  110. data/spec/support/providers/example_provider.rb +11 -0
  111. metadata +97 -34
  112. data/.travis.yml +0 -57
  113. data/gemfiles/active_record-rails40.gemfile +0 -7
  114. data/gemfiles/active_record-rails41.gemfile +0 -7
  115. data/gemfiles/active_record-rails42.gemfile +0 -7
  116. data/spec/rails_app/config/initializers/secret_token.rb +0 -7
@@ -1,10 +1,10 @@
1
1
  class SorceryActivityLogging < <%= migration_class_name %>
2
2
  def change
3
- add_column :<%= model_class_name.tableize %>, :last_login_at, :datetime, :default => nil
4
- add_column :<%= model_class_name.tableize %>, :last_logout_at, :datetime, :default => nil
5
- add_column :<%= model_class_name.tableize %>, :last_activity_at, :datetime, :default => nil
6
- add_column :<%= model_class_name.tableize %>, :last_login_from_ip_address, :string, :default => nil
3
+ add_column :<%= tableized_model_class %>, :last_login_at, :datetime, default: nil
4
+ add_column :<%= tableized_model_class %>, :last_logout_at, :datetime, default: nil
5
+ add_column :<%= tableized_model_class %>, :last_activity_at, :datetime, default: nil
6
+ add_column :<%= tableized_model_class %>, :last_login_from_ip_address, :string, default: nil
7
7
 
8
- add_index :<%= model_class_name.tableize %>, [:last_logout_at, :last_activity_at]
8
+ add_index :<%= tableized_model_class %>, [:last_logout_at, :last_activity_at]
9
9
  end
10
10
  end
@@ -1,9 +1,9 @@
1
1
  class SorceryBruteForceProtection < <%= migration_class_name %>
2
2
  def change
3
- add_column :<%= model_class_name.tableize %>, :failed_logins_count, :integer, :default => 0
4
- add_column :<%= model_class_name.tableize %>, :lock_expires_at, :datetime, :default => nil
5
- add_column :<%= model_class_name.tableize %>, :unlock_token, :string, :default => nil
3
+ add_column :<%= tableized_model_class %>, :failed_logins_count, :integer, default: 0
4
+ add_column :<%= tableized_model_class %>, :lock_expires_at, :datetime, default: nil
5
+ add_column :<%= tableized_model_class %>, :unlock_token, :string, default: nil
6
6
 
7
- add_index :<%= model_class_name.tableize %>, :unlock_token
7
+ add_index :<%= tableized_model_class %>, :unlock_token
8
8
  end
9
9
  end
@@ -1,13 +1,13 @@
1
1
  class SorceryCore < <%= migration_class_name %>
2
2
  def change
3
- create_table :<%= model_class_name.tableize %> do |t|
4
- t.string :email, :null => false
3
+ create_table :<%= tableized_model_class %> do |t|
4
+ t.string :email, null: false
5
5
  t.string :crypted_password
6
6
  t.string :salt
7
7
 
8
- t.timestamps :null => false
8
+ t.timestamps null: false
9
9
  end
10
10
 
11
- add_index :<%= model_class_name.tableize %>, :email, unique: true
11
+ add_index :<%= tableized_model_class %>, :email, unique: true
12
12
  end
13
13
  end
@@ -1,10 +1,10 @@
1
1
  class SorceryExternal < <%= migration_class_name %>
2
2
  def change
3
3
  create_table :authentications do |t|
4
- t.integer :<%= model_class_name.tableize.singularize %>_id, :null => false
5
- t.string :provider, :uid, :null => false
4
+ t.integer :<%= tableized_model_class.singularize %>_id, null: false
5
+ t.string :provider, :uid, null: false
6
6
 
7
- t.timestamps :null => false
7
+ t.timestamps null: false
8
8
  end
9
9
 
10
10
  add_index :authentications, [:provider, :uid]
@@ -0,0 +1,9 @@
1
+ class SorceryMagicLogin < <%= migration_class_name %>
2
+ def change
3
+ add_column :<%= tableized_model_class %>, :magic_login_token, :string, default: nil
4
+ add_column :<%= tableized_model_class %>, :magic_login_token_expires_at, :datetime, default: nil
5
+ add_column :<%= tableized_model_class %>, :magic_login_email_sent_at, :datetime, default: nil
6
+
7
+ add_index :<%= tableized_model_class %>, :magic_login_token
8
+ end
9
+ end
@@ -1,8 +1,8 @@
1
1
  class SorceryRememberMe < <%= migration_class_name %>
2
2
  def change
3
- add_column :<%= model_class_name.tableize %>, :remember_me_token, :string, :default => nil
4
- add_column :<%= model_class_name.tableize %>, :remember_me_token_expires_at, :datetime, :default => nil
3
+ add_column :<%= tableized_model_class %>, :remember_me_token, :string, default: nil
4
+ add_column :<%= tableized_model_class %>, :remember_me_token_expires_at, :datetime, default: nil
5
5
 
6
- add_index :<%= model_class_name.tableize %>, :remember_me_token
6
+ add_index :<%= tableized_model_class %>, :remember_me_token
7
7
  end
8
8
  end
@@ -1,9 +1,10 @@
1
1
  class SorceryResetPassword < <%= migration_class_name %>
2
2
  def change
3
- add_column :<%= model_class_name.tableize %>, :reset_password_token, :string, :default => nil
4
- add_column :<%= model_class_name.tableize %>, :reset_password_token_expires_at, :datetime, :default => nil
5
- add_column :<%= model_class_name.tableize %>, :reset_password_email_sent_at, :datetime, :default => nil
3
+ add_column :<%= tableized_model_class %>, :reset_password_token, :string, default: nil
4
+ add_column :<%= tableized_model_class %>, :reset_password_token_expires_at, :datetime, default: nil
5
+ add_column :<%= tableized_model_class %>, :reset_password_email_sent_at, :datetime, default: nil
6
+ add_column :<%= tableized_model_class %>, :access_count_to_reset_password_page, :integer, default: 0
6
7
 
7
- add_index :<%= model_class_name.tableize %>, :reset_password_token
8
+ add_index :<%= tableized_model_class %>, :reset_password_token
8
9
  end
9
10
  end
@@ -1,9 +1,9 @@
1
1
  class SorceryUserActivation < <%= migration_class_name %>
2
2
  def change
3
- add_column :<%= model_class_name.tableize %>, :activation_state, :string, :default => nil
4
- add_column :<%= model_class_name.tableize %>, :activation_token, :string, :default => nil
5
- add_column :<%= model_class_name.tableize %>, :activation_token_expires_at, :datetime, :default => nil
3
+ add_column :<%= tableized_model_class %>, :activation_state, :string, default: nil
4
+ add_column :<%= tableized_model_class %>, :activation_token, :string, default: nil
5
+ add_column :<%= tableized_model_class %>, :activation_token_expires_at, :datetime, default: nil
6
6
 
7
- add_index :<%= model_class_name.tableize %>, :activation_token
7
+ add_index :<%= tableized_model_class %>, :activation_token
8
8
  end
9
9
  end
data/lib/sorcery.rb CHANGED
@@ -18,6 +18,7 @@ module Sorcery
18
18
  require 'sorcery/model/submodules/activity_logging'
19
19
  require 'sorcery/model/submodules/brute_force_protection'
20
20
  require 'sorcery/model/submodules/external'
21
+ require 'sorcery/model/submodules/magic_login'
21
22
  end
22
23
  end
23
24
 
@@ -56,6 +57,7 @@ module Sorcery
56
57
  module Rails
57
58
  require 'sorcery/test_helpers/rails/controller'
58
59
  require 'sorcery/test_helpers/rails/integration'
60
+ require 'sorcery/test_helpers/rails/request'
59
61
  end
60
62
 
61
63
  module Internal
@@ -6,12 +6,13 @@ module Sorcery
6
6
  @model.send(:"#{name}=", value)
7
7
  end
8
8
  primary_key = @model.class.primary_key
9
- @model.class.where(:"#{primary_key}" => @model.send(:"#{primary_key}")).update_all(attrs)
9
+ updated_count = @model.class.where(:"#{primary_key}" => @model.send(:"#{primary_key}")).update_all(attrs)
10
+ updated_count == 1
10
11
  end
11
12
 
12
13
  def save(options = {})
13
14
  mthd = options.delete(:raise_on_failure) ? :save! : :save
14
- @model.send(mthd, options)
15
+ @model.send(mthd, **options)
15
16
  end
16
17
 
17
18
  def increment(field)
@@ -34,7 +35,7 @@ module Sorcery
34
35
  end
35
36
 
36
37
  def define_callback(time, event, method_name, options = {})
37
- @klass.send "#{time}_#{event}", method_name, options.slice(:if)
38
+ @klass.send "#{time}_#{event}", method_name, **options.slice(:if, :on)
38
39
  end
39
40
 
40
41
  def find_by_oauth_credentials(provider, uid)
@@ -10,7 +10,7 @@ module Sorcery
10
10
  attrs[name] = value.utc if value.is_a?(ActiveSupport::TimeWithZone)
11
11
  @model.send(:"#{name}=", value)
12
12
  end
13
- @model.class.where(:_id => @model.id).update_all(attrs)
13
+ @model.class.where(_id: @model.id).update_all(attrs)
14
14
  end
15
15
 
16
16
  def update_attribute(name, value)
@@ -23,21 +23,29 @@ module Sorcery
23
23
  end
24
24
 
25
25
  def mongoid_4?
26
- Gem::Version.new(::Mongoid::VERSION) >= Gem::Version.new("4.0.0.alpha")
26
+ Gem::Version.new(::Mongoid::VERSION) >= Gem::Version.new('4.0.0.alpha')
27
27
  end
28
28
 
29
29
  class << self
30
-
31
- def define_field(name, type, options={})
30
+ def define_field(name, type, options = {})
32
31
  @klass.field name, options.slice(:default).merge(type: type)
33
32
  end
34
33
 
35
- def define_callback(time, event, method_name, options={})
36
- @klass.send "#{time}_#{event}", method_name, options.slice(:if)
34
+ def define_callback(time, event, method_name, options = {})
35
+ @klass.send callback_name(time, event, options), method_name, options.slice(:if)
36
+ end
37
+
38
+ def callback_name(time, event, options)
39
+ if event == :commit
40
+ options[:on] == :create ? "#{time}_create" : "#{time}_save"
41
+ else
42
+ "#{time}_#{event}"
43
+ end
37
44
  end
38
45
 
39
46
  def credential_regex(credential)
40
- return { :$regex => /^#{Regexp.escape(credential)}$/i } if (@klass.sorcery_config.downcase_username_before_authenticating)
47
+ return { :$regex => /^#{Regexp.escape(credential)}$/i } if @klass.sorcery_config.downcase_username_before_authenticating
48
+
41
49
  credential
42
50
  end
43
51
 
@@ -73,7 +81,7 @@ module Sorcery
73
81
  end
74
82
 
75
83
  def find_by_username(username)
76
- query = @klass.sorcery_config.username_attribute_names.map {|name| {name => username}}
84
+ query = @klass.sorcery_config.username_attribute_names.map { |name| { name => username } }
77
85
  @klass.any_of(*query).first
78
86
  end
79
87
 
@@ -87,9 +95,13 @@ module Sorcery
87
95
 
88
96
  def get_current_users
89
97
  config = @klass.sorcery_config
90
- @klass.where(config.last_activity_at_attribute_name.ne => nil) \
91
- .where("this.#{config.last_logout_at_attribute_name} == null || this.#{config.last_activity_at_attribute_name} > this.#{config.last_logout_at_attribute_name}") \
92
- .where(config.last_activity_at_attribute_name.gt => config.activity_timeout.seconds.ago.utc).order_by([:_id,:asc])
98
+ @klass.where(
99
+ config.last_activity_at_attribute_name.ne => nil
100
+ ).where(
101
+ "this.#{config.last_logout_at_attribute_name} == null || this.#{config.last_activity_at_attribute_name} > this.#{config.last_logout_at_attribute_name}"
102
+ ).where(
103
+ config.last_activity_at_attribute_name.gt => config.activity_timeout.seconds.ago.utc
104
+ ).order_by(%i[_id asc])
93
105
  end
94
106
  end
95
107
  end
@@ -4,11 +4,14 @@ module Sorcery
4
4
  klass.class_eval do
5
5
  include InstanceMethods
6
6
  Config.submodules.each do |mod|
7
+ # FIXME: Is there a cleaner way to handle missing submodules?
8
+ # rubocop:disable Lint/HandleExceptions
7
9
  begin
8
10
  include Submodules.const_get(mod.to_s.split('_').map(&:capitalize).join)
9
11
  rescue NameError
10
12
  # don't stop on a missing submodule.
11
13
  end
14
+ # rubocop:enable Lint/HandleExceptions
12
15
  end
13
16
  end
14
17
  Config.update!
@@ -20,10 +23,13 @@ module Sorcery
20
23
  # Will trigger auto-login attempts via the call to logged_in?
21
24
  # If all attempts to auto-login fail, the failure callback will be called.
22
25
  def require_login
23
- unless logged_in?
24
- session[:return_to_url] = request.url if Config.save_return_to_url && request.get? && !request.xhr?
25
- send(Config.not_authenticated_action)
26
+ return if logged_in?
27
+
28
+ if Config.save_return_to_url && request.get? && !request.xhr? && !request.format.json?
29
+ session[:return_to_url] = request.url
26
30
  end
31
+
32
+ send(Config.not_authenticated_action)
27
33
  end
28
34
 
29
35
  # Takes credentials and returns a user on successful authentication.
@@ -37,7 +43,10 @@ module Sorcery
37
43
 
38
44
  yield(user, failure_reason) if block_given?
39
45
 
46
+ # FIXME: Does using `break` or `return nil` change functionality?
47
+ # rubocop:disable Lint/NonLocalExitFromIterator
40
48
  return
49
+ # rubocop:enable Lint/NonLocalExitFromIterator
41
50
  end
42
51
 
43
52
  old_session = session.dup.to_hash
@@ -47,30 +56,26 @@ module Sorcery
47
56
  end
48
57
  form_authenticity_token
49
58
 
50
- auto_login(user)
59
+ auto_login(user, credentials[2])
51
60
  after_login!(user, credentials)
52
61
 
53
62
  block_given? ? yield(current_user, nil) : current_user
54
63
  end
55
64
  end
56
65
 
57
- # put this into the catch block to rescue undefined method `destroy_session'
58
- # hotfix for https://github.com/NoamB/sorcery/issues/464
59
- # can be removed when Rails 4.1 is out
60
66
  def reset_sorcery_session
61
67
  reset_session # protect from session fixation attacks
62
- rescue NoMethodError
63
68
  end
64
69
 
65
70
  # Resets the session and runs hooks before and after.
66
71
  def logout
67
- if logged_in?
68
- user = current_user
69
- before_logout!
70
- @current_user = nil
71
- reset_sorcery_session
72
- after_logout!(user)
73
- end
72
+ return unless logged_in?
73
+
74
+ user = current_user
75
+ before_logout!
76
+ @current_user = nil
77
+ reset_sorcery_session
78
+ after_logout!(user)
74
79
  end
75
80
 
76
81
  def logged_in?
@@ -153,8 +158,14 @@ module Sorcery
153
158
  Config.after_logout.each { |c| send(c, user) }
154
159
  end
155
160
 
161
+ def after_remember_me!(user)
162
+ Config.after_remember_me.each { |c| send(c, user) }
163
+ end
164
+
156
165
  def user_class
157
166
  @user_class ||= Config.user_class.to_s.constantize
167
+ rescue NameError
168
+ raise ArgumentError, 'You have incorrectly defined user_class or have forgotten to define it in intitializer file (config.user_class = \'User\').'
158
169
  end
159
170
  end
160
171
  end
@@ -18,17 +18,19 @@ module Sorcery
18
18
  attr_accessor :after_failed_login
19
19
  attr_accessor :before_logout
20
20
  attr_accessor :after_logout
21
+ attr_accessor :after_remember_me
21
22
 
22
23
  def init!
23
24
  @defaults = {
24
25
  :@user_class => nil,
25
26
  :@submodules => [],
26
27
  :@not_authenticated_action => :not_authenticated,
27
- :@login_sources => [],
28
- :@after_login => [],
29
- :@after_failed_login => [],
30
- :@before_logout => [],
31
- :@after_logout => [],
28
+ :@login_sources => Set.new,
29
+ :@after_login => Set.new,
30
+ :@after_failed_login => Set.new,
31
+ :@before_logout => Set.new,
32
+ :@after_logout => Set.new,
33
+ :@after_remember_me => Set.new,
32
34
  :@save_return_to_url => true,
33
35
  :@cookie_domain => nil
34
36
  }
@@ -30,9 +30,11 @@ module Sorcery
30
30
  end
31
31
  merge_activity_logging_defaults!
32
32
  end
33
- Config.after_login << :register_login_time_to_db
34
- Config.after_login << :register_last_ip_address
35
- Config.before_logout << :register_logout_time_to_db
33
+
34
+ Config.after_login << :register_login_time_to_db
35
+ Config.after_login << :register_last_ip_address
36
+ Config.before_logout << :register_logout_time_to_db
37
+
36
38
  base.after_action :register_last_activity_time_to_db
37
39
  end
38
40
 
@@ -43,6 +45,7 @@ module Sorcery
43
45
  # This runs as a hook just after a successful login.
44
46
  def register_login_time_to_db(user, _credentials)
45
47
  return unless Config.register_login_time
48
+
46
49
  user.set_last_login_at(Time.now.in_time_zone)
47
50
  end
48
51
 
@@ -50,6 +53,7 @@ module Sorcery
50
53
  # This runs as a hook just before a logout.
51
54
  def register_logout_time_to_db
52
55
  return unless Config.register_logout_time
56
+
53
57
  current_user.set_last_logout_at(Time.now.in_time_zone)
54
58
  end
55
59
 
@@ -58,6 +62,7 @@ module Sorcery
58
62
  def register_last_activity_time_to_db
59
63
  return unless Config.register_last_activity_time
60
64
  return unless logged_in?
65
+
61
66
  current_user.set_last_activity_at(Time.now.in_time_zone)
62
67
  end
63
68
 
@@ -65,6 +70,7 @@ module Sorcery
65
70
  # This runs as a hook just after a successful login.
66
71
  def register_last_ip_address(_user, _credentials)
67
72
  return unless Config.register_last_ip_address
73
+
68
74
  current_user.set_last_ip_address(request.remote_ip)
69
75
  end
70
76
  end
@@ -23,6 +23,11 @@ module Sorcery
23
23
  require 'sorcery/providers/slack'
24
24
  require 'sorcery/providers/wechat'
25
25
  require 'sorcery/providers/microsoft'
26
+ require 'sorcery/providers/instagram'
27
+ require 'sorcery/providers/auth0'
28
+ require 'sorcery/providers/line'
29
+ require 'sorcery/providers/discord'
30
+ require 'sorcery/providers/battlenet'
26
31
 
27
32
  Config.module_eval do
28
33
  class << self
@@ -33,17 +38,17 @@ module Sorcery
33
38
  @external_providers = providers
34
39
 
35
40
  providers.each do |name|
36
- class_eval <<-E
41
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
37
42
  def self.#{name}
38
- @#{name} ||= Sorcery::Providers.const_get('#{name}'.to_s.capitalize).new
43
+ @#{name} ||= Sorcery::Providers.const_get('#{name}'.to_s.classify).new
39
44
  end
40
- E
45
+ RUBY
41
46
  end
42
47
  end
43
48
 
44
49
  def merge_external_defaults!
45
50
  @defaults.merge!(:@external_providers => [],
46
- :@ca_file => File.join(File.expand_path(File.dirname(__FILE__)), '../../protocols/certs/ca-bundle.crt'))
51
+ :@ca_file => File.join(__dir__, '../../protocols/certs/ca-bundle.crt'))
47
52
  end
48
53
  end
49
54
  merge_external_defaults!
@@ -56,6 +61,7 @@ module Sorcery
56
61
  # save the singleton ProviderClient instance into @provider
57
62
  def sorcery_get_provider(provider_name)
58
63
  return unless Config.external_providers.include?(provider_name.to_sym)
64
+
59
65
  Config.send(provider_name.to_sym)
60
66
  end
61
67
 
@@ -64,12 +70,11 @@ module Sorcery
64
70
  def sorcery_login_url(provider_name, args = {})
65
71
  @provider = sorcery_get_provider provider_name
66
72
  sorcery_fixup_callback_url @provider
67
- if @provider.respond_to?(:login_url) && @provider.has_callback?
68
- @provider.state = args[:state]
69
- return @provider.login_url(params, session)
70
- else
71
- return nil
72
- end
73
+
74
+ return nil unless @provider.respond_to?(:login_url) && @provider.has_callback?
75
+
76
+ @provider.state = args[:state]
77
+ @provider.login_url(params, session)
73
78
  end
74
79
 
75
80
  # get the user hash from a provider using information from the params and session.
@@ -88,6 +93,7 @@ module Sorcery
88
93
  # cache them in instance variables.
89
94
  @access_token ||= @provider.process_callback(params, session) # sends request to oauth agent to get the token
90
95
  @user_hash ||= @provider.get_user_hash(@access_token) # uses the token to send another request to the oauth agent requesting user info
96
+ nil
91
97
  end
92
98
 
93
99
  # for backwards compatibility
@@ -98,14 +104,15 @@ module Sorcery
98
104
  # this method should be somewhere else. It only does something once per application per provider.
99
105
  def sorcery_fixup_callback_url(provider)
100
106
  provider.original_callback_url ||= provider.callback_url
101
- if provider.original_callback_url.present? && provider.original_callback_url[0] == '/'
102
- uri = URI.parse(request.url.gsub(/\?.*$/, ''))
103
- uri.path = ''
104
- uri.query = nil
105
- uri.scheme = 'https' if request.env['HTTP_X_FORWARDED_PROTO'] == 'https'
106
- host = uri.to_s
107
- provider.callback_url = "#{host}#{@provider.original_callback_url}"
108
- end
107
+
108
+ return unless provider.original_callback_url.present? && provider.original_callback_url[0] == '/'
109
+
110
+ uri = URI.parse(request.url.gsub(/\?.*$/, ''))
111
+ uri.path = ''
112
+ uri.query = nil
113
+ uri.scheme = 'https' if request.env['HTTP_X_FORWARDED_PROTO'] == 'https'
114
+ host = uri.to_s
115
+ provider.callback_url = "#{host}#{@provider.original_callback_url}"
109
116
  end
110
117
 
111
118
  # sends user to authenticate at the provider's website.
@@ -118,26 +125,26 @@ module Sorcery
118
125
  def login_from(provider_name, should_remember = false)
119
126
  sorcery_fetch_user_hash provider_name
120
127
 
121
- if user = user_class.load_from_provider(provider_name, @user_hash[:uid].to_s)
122
- # we found the user.
123
- # clear the session
124
- return_to_url = session[:return_to_url]
125
- reset_sorcery_session
126
- session[:return_to_url] = return_to_url
128
+ return unless (user = user_class.load_from_provider(provider_name, @user_hash[:uid].to_s))
127
129
 
128
- # sign in the user
129
- auto_login(user, should_remember)
130
- after_login!(user)
130
+ # we found the user.
131
+ # clear the session
132
+ return_to_url = session[:return_to_url]
133
+ reset_sorcery_session
134
+ session[:return_to_url] = return_to_url
131
135
 
132
- # return the user
133
- user
134
- end
136
+ # sign in the user
137
+ auto_login(user, should_remember)
138
+ after_login!(user)
139
+
140
+ # return the user
141
+ user
135
142
  end
136
143
 
137
144
  # If user is logged, he can add all available providers into his account
138
145
  def add_provider_to_user(provider_name)
139
146
  sorcery_fetch_user_hash provider_name
140
- config = user_class.sorcery_config
147
+ # config = user_class.sorcery_config # TODO: Unused, remove?
141
148
 
142
149
  current_user.add_provider_to_user(provider_name.to_s, @user_hash[:uid].to_s)
143
150
  end
@@ -181,19 +188,28 @@ module Sorcery
181
188
  #
182
189
  def create_from(provider_name, &block)
183
190
  sorcery_fetch_user_hash provider_name
184
- config = user_class.sorcery_config
191
+ # config = user_class.sorcery_config # TODO: Unused, remove?
185
192
 
186
193
  attrs = user_attrs(@provider.user_info_mapping, @user_hash)
187
194
  @user = user_class.create_from_provider(provider_name, @user_hash[:uid], attrs, &block)
188
195
  end
189
196
 
197
+ # follows the same patterns as create_from, but builds the user instead of creating
198
+ def build_from(provider_name, &block)
199
+ sorcery_fetch_user_hash provider_name
200
+ # config = user_class.sorcery_config # TODO: Unused, remove?
201
+
202
+ attrs = user_attrs(@provider.user_info_mapping, @user_hash)
203
+ @user = user_class.build_from_provider(attrs, &block)
204
+ end
205
+
190
206
  def user_attrs(user_info_mapping, user_hash)
191
207
  attrs = {}
192
208
  user_info_mapping.each do |k, v|
193
209
  if (varr = v.split('/')).size > 1
194
210
  attribute_value = begin
195
211
  varr.inject(user_hash[:user_info]) { |hash, value| hash[value] }
196
- rescue
212
+ rescue StandardError
197
213
  nil
198
214
  end
199
215
  attribute_value.nil? ? attrs : attrs.merge!(k => attribute_value)