authlogic 3.8.0 → 6.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 (150) hide show
  1. checksums.yaml +7 -0
  2. data/lib/authlogic/acts_as_authentic/base.rb +33 -36
  3. data/lib/authlogic/acts_as_authentic/email.rb +8 -141
  4. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +17 -10
  5. data/lib/authlogic/acts_as_authentic/login.rb +14 -165
  6. data/lib/authlogic/acts_as_authentic/magic_columns.rb +13 -10
  7. data/lib/authlogic/acts_as_authentic/password.rb +186 -254
  8. data/lib/authlogic/acts_as_authentic/perishable_token.rb +30 -22
  9. data/lib/authlogic/acts_as_authentic/persistence_token.rb +19 -18
  10. data/lib/authlogic/acts_as_authentic/queries/case_sensitivity.rb +53 -0
  11. data/lib/authlogic/acts_as_authentic/queries/find_with_case.rb +83 -0
  12. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +94 -62
  13. data/lib/authlogic/acts_as_authentic/single_access_token.rb +28 -14
  14. data/lib/authlogic/config.rb +29 -10
  15. data/lib/authlogic/controller_adapters/abstract_adapter.rb +43 -13
  16. data/lib/authlogic/controller_adapters/rack_adapter.rb +11 -5
  17. data/lib/authlogic/controller_adapters/rails_adapter.rb +11 -29
  18. data/lib/authlogic/controller_adapters/sinatra_adapter.rb +8 -2
  19. data/lib/authlogic/cookie_credentials.rb +63 -0
  20. data/lib/authlogic/crypto_providers/bcrypt.rb +24 -18
  21. data/lib/authlogic/crypto_providers/md5/v2.rb +35 -0
  22. data/lib/authlogic/crypto_providers/md5.rb +8 -6
  23. data/lib/authlogic/crypto_providers/scrypt.rb +24 -17
  24. data/lib/authlogic/crypto_providers/sha1/v2.rb +41 -0
  25. data/lib/authlogic/crypto_providers/sha1.rb +12 -5
  26. data/lib/authlogic/crypto_providers/sha256/v2.rb +58 -0
  27. data/lib/authlogic/crypto_providers/sha256.rb +18 -9
  28. data/lib/authlogic/crypto_providers/sha512/v2.rb +39 -0
  29. data/lib/authlogic/crypto_providers/sha512.rb +9 -26
  30. data/lib/authlogic/crypto_providers.rb +77 -1
  31. data/lib/authlogic/errors.rb +35 -0
  32. data/lib/authlogic/i18n/translator.rb +4 -1
  33. data/lib/authlogic/i18n.rb +29 -20
  34. data/lib/authlogic/random.rb +12 -28
  35. data/lib/authlogic/session/base.rb +2087 -33
  36. data/lib/authlogic/session/magic_column/assigns_last_request_at.rb +46 -0
  37. data/lib/authlogic/test_case/mock_controller.rb +7 -4
  38. data/lib/authlogic/test_case/mock_cookie_jar.rb +19 -3
  39. data/lib/authlogic/test_case/mock_logger.rb +2 -0
  40. data/lib/authlogic/test_case/mock_request.rb +8 -3
  41. data/lib/authlogic/test_case/rails_request_adapter.rb +5 -2
  42. data/lib/authlogic/test_case.rb +74 -2
  43. data/lib/authlogic/version.rb +22 -0
  44. data/lib/authlogic.rb +33 -54
  45. metadata +208 -234
  46. data/.github/ISSUE_TEMPLATE.md +0 -13
  47. data/.gitignore +0 -14
  48. data/.rubocop.yml +0 -33
  49. data/.rubocop_todo.yml +0 -391
  50. data/.travis.yml +0 -48
  51. data/CHANGELOG.md +0 -5
  52. data/CONTRIBUTING.md +0 -60
  53. data/Gemfile +0 -5
  54. data/LICENSE +0 -20
  55. data/README.md +0 -294
  56. data/Rakefile +0 -21
  57. data/authlogic.gemspec +0 -27
  58. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +0 -70
  59. data/lib/authlogic/acts_as_authentic/validations_scope.rb +0 -32
  60. data/lib/authlogic/authenticates_many/association.rb +0 -50
  61. data/lib/authlogic/authenticates_many/base.rb +0 -65
  62. data/lib/authlogic/crypto_providers/aes256.rb +0 -66
  63. data/lib/authlogic/crypto_providers/wordpress.rb +0 -43
  64. data/lib/authlogic/regex.rb +0 -48
  65. data/lib/authlogic/session/activation.rb +0 -70
  66. data/lib/authlogic/session/active_record_trickery.rb +0 -61
  67. data/lib/authlogic/session/brute_force_protection.rb +0 -120
  68. data/lib/authlogic/session/callbacks.rb +0 -105
  69. data/lib/authlogic/session/cookies.rb +0 -244
  70. data/lib/authlogic/session/existence.rb +0 -93
  71. data/lib/authlogic/session/foundation.rb +0 -55
  72. data/lib/authlogic/session/http_auth.rb +0 -100
  73. data/lib/authlogic/session/id.rb +0 -48
  74. data/lib/authlogic/session/klass.rb +0 -70
  75. data/lib/authlogic/session/magic_columns.rb +0 -116
  76. data/lib/authlogic/session/magic_states.rb +0 -76
  77. data/lib/authlogic/session/params.rb +0 -116
  78. data/lib/authlogic/session/password.rb +0 -308
  79. data/lib/authlogic/session/perishable_token.rb +0 -23
  80. data/lib/authlogic/session/persistence.rb +0 -71
  81. data/lib/authlogic/session/priority_record.rb +0 -35
  82. data/lib/authlogic/session/scopes.rb +0 -119
  83. data/lib/authlogic/session/session.rb +0 -67
  84. data/lib/authlogic/session/timeout.rb +0 -103
  85. data/lib/authlogic/session/unauthorized_record.rb +0 -51
  86. data/lib/authlogic/session/validation.rb +0 -93
  87. data/test/acts_as_authentic_test/base_test.rb +0 -25
  88. data/test/acts_as_authentic_test/email_test.rb +0 -240
  89. data/test/acts_as_authentic_test/logged_in_status_test.rb +0 -62
  90. data/test/acts_as_authentic_test/login_test.rb +0 -156
  91. data/test/acts_as_authentic_test/magic_columns_test.rb +0 -27
  92. data/test/acts_as_authentic_test/password_test.rb +0 -249
  93. data/test/acts_as_authentic_test/perishable_token_test.rb +0 -90
  94. data/test/acts_as_authentic_test/persistence_token_test.rb +0 -56
  95. data/test/acts_as_authentic_test/restful_authentication_test.rb +0 -37
  96. data/test/acts_as_authentic_test/session_maintenance_test.rb +0 -96
  97. data/test/acts_as_authentic_test/single_access_test.rb +0 -44
  98. data/test/authenticates_many_test.rb +0 -31
  99. data/test/config_test.rb +0 -36
  100. data/test/crypto_provider_test/aes256_test.rb +0 -14
  101. data/test/crypto_provider_test/bcrypt_test.rb +0 -14
  102. data/test/crypto_provider_test/scrypt_test.rb +0 -14
  103. data/test/crypto_provider_test/sha1_test.rb +0 -23
  104. data/test/crypto_provider_test/sha256_test.rb +0 -14
  105. data/test/crypto_provider_test/sha512_test.rb +0 -14
  106. data/test/fixtures/companies.yml +0 -5
  107. data/test/fixtures/employees.yml +0 -17
  108. data/test/fixtures/projects.yml +0 -3
  109. data/test/fixtures/users.yml +0 -41
  110. data/test/gemfiles/Gemfile.rails-3.2.x +0 -7
  111. data/test/gemfiles/Gemfile.rails-4.0.x +0 -7
  112. data/test/gemfiles/Gemfile.rails-4.1.x +0 -7
  113. data/test/gemfiles/Gemfile.rails-4.2.x +0 -7
  114. data/test/gemfiles/Gemfile.rails-5.0.x +0 -6
  115. data/test/gemfiles/Gemfile.rails-5.1.x +0 -6
  116. data/test/gemfiles/Gemfile.rails-5.2.x +0 -6
  117. data/test/i18n/lol.yml +0 -4
  118. data/test/i18n_test.rb +0 -33
  119. data/test/libs/affiliate.rb +0 -7
  120. data/test/libs/company.rb +0 -6
  121. data/test/libs/employee.rb +0 -7
  122. data/test/libs/employee_session.rb +0 -2
  123. data/test/libs/ldaper.rb +0 -3
  124. data/test/libs/project.rb +0 -3
  125. data/test/libs/user.rb +0 -7
  126. data/test/libs/user_session.rb +0 -25
  127. data/test/random_test.rb +0 -43
  128. data/test/session_test/activation_test.rb +0 -43
  129. data/test/session_test/active_record_trickery_test.rb +0 -75
  130. data/test/session_test/brute_force_protection_test.rb +0 -108
  131. data/test/session_test/callbacks_test.rb +0 -34
  132. data/test/session_test/cookies_test.rb +0 -201
  133. data/test/session_test/credentials_test.rb +0 -0
  134. data/test/session_test/existence_test.rb +0 -75
  135. data/test/session_test/foundation_test.rb +0 -6
  136. data/test/session_test/http_auth_test.rb +0 -56
  137. data/test/session_test/id_test.rb +0 -17
  138. data/test/session_test/klass_test.rb +0 -40
  139. data/test/session_test/magic_columns_test.rb +0 -62
  140. data/test/session_test/magic_states_test.rb +0 -58
  141. data/test/session_test/params_test.rb +0 -53
  142. data/test/session_test/password_test.rb +0 -105
  143. data/test/session_test/perishability_test.rb +0 -15
  144. data/test/session_test/persistence_test.rb +0 -32
  145. data/test/session_test/scopes_test.rb +0 -60
  146. data/test/session_test/session_test.rb +0 -78
  147. data/test/session_test/timeout_test.rb +0 -82
  148. data/test/session_test/unauthorized_record_test.rb +0 -13
  149. data/test/session_test/validation_test.rb +0 -23
  150. data/test/test_helper.rb +0 -233
@@ -1,18 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Authlogic
2
4
  module ControllerAdapters # :nodoc:
3
- # Allows you to use Authlogic in any framework you want, not just rails. See the RailsAdapter
4
- # for an example of how to adapt Authlogic to work with your framework.
5
+ # Allows you to use Authlogic in any framework you want, not just rails. See
6
+ # the RailsAdapter for an example of how to adapt Authlogic to work with
7
+ # your framework.
5
8
  class AbstractAdapter
9
+ E_COOKIE_DOMAIN_ADAPTER = "The cookie_domain method has not been " \
10
+ "implemented by the controller adapter"
11
+
6
12
  attr_accessor :controller
7
13
 
8
14
  def initialize(controller)
9
15
  self.controller = controller
10
16
  end
11
17
 
12
- def authenticate_with_http_basic(&block)
18
+ def authenticate_with_http_basic
13
19
  @auth = Rack::Auth::Basic::Request.new(controller.request.env)
14
- if @auth.provided? and @auth.basic?
15
- block.call(*@auth.credentials)
20
+ if @auth.provided? && @auth.basic?
21
+ yield(*@auth.credentials)
16
22
  else
17
23
  false
18
24
  end
@@ -23,7 +29,7 @@ module Authlogic
23
29
  end
24
30
 
25
31
  def cookie_domain
26
- raise NotImplementedError.new("The cookie_domain method has not been implemented by the controller adapter")
32
+ raise NotImplementedError, E_COOKIE_DOMAIN_ADAPTER
27
33
  end
28
34
 
29
35
  def params
@@ -50,19 +56,43 @@ module Authlogic
50
56
  controller.send(:single_access_allowed?)
51
57
  end
52
58
 
53
- def responds_to_last_request_update_allowed?
54
- controller.respond_to?(:last_request_update_allowed?, true)
59
+ # You can disable the updating of `last_request_at`
60
+ # on a per-controller basis.
61
+ #
62
+ # # in your controller
63
+ # def last_request_update_allowed?
64
+ # false
65
+ # end
66
+ #
67
+ # For example, what if you had a javascript function that polled the
68
+ # server updating how much time is left in their session before it
69
+ # times out. Obviously you would want to ignore this request, because
70
+ # then the user would never time out. So you can do something like
71
+ # this in your controller:
72
+ #
73
+ # def last_request_update_allowed?
74
+ # action_name != "update_session_time_left"
75
+ # end
76
+ #
77
+ # See `authlogic/session/magic_columns.rb` to learn more about the
78
+ # `last_request_at` column itself.
79
+ def last_request_update_allowed?
80
+ if controller.respond_to?(:last_request_update_allowed?, true)
81
+ controller.send(:last_request_update_allowed?)
82
+ else
83
+ true
84
+ end
55
85
  end
56
86
 
57
- def last_request_update_allowed?
58
- controller.send(:last_request_update_allowed?)
87
+ def respond_to_missing?(*args)
88
+ super(*args) || controller.respond_to?(*args)
59
89
  end
60
90
 
61
91
  private
62
92
 
63
- def method_missing(id, *args, &block)
64
- controller.send(id, *args, &block)
65
- end
93
+ def method_missing(id, *args, &block)
94
+ controller.send(id, *args, &block)
95
+ end
66
96
  end
67
97
  end
68
98
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Authlogic
2
4
  module ControllerAdapters
3
5
  # Adapter for authlogic to make it function as a Rack middleware.
@@ -32,7 +34,7 @@ module Authlogic
32
34
  # # Authlogic options go here
33
35
  # end
34
36
  #
35
- # class User < ActiveRecord::Base
37
+ # class User < ApplicationRecord
36
38
  # acts_as_authentic
37
39
  # end
38
40
  #
@@ -48,7 +50,7 @@ module Authlogic
48
50
  end
49
51
 
50
52
  def remote_ip
51
- self.ip
53
+ ip
52
54
  end
53
55
  end
54
56
 
@@ -56,10 +58,14 @@ module Authlogic
56
58
  Authlogic::Session::Base.controller = self
57
59
  end
58
60
 
59
- # Rack Requests stores cookies with not just the value, but also with flags and expire information in the hash.
60
- # Authlogic does not like this, so we drop everything except the cookie value
61
+ # Rack Requests stores cookies with not just the value, but also with
62
+ # flags and expire information in the hash. Authlogic does not like this,
63
+ # so we drop everything except the cookie value.
61
64
  def cookies
62
- controller.cookies.map { |key, value_hash| { key => value_hash[:value] } }.inject(:merge) || {}
65
+ controller
66
+ .cookies
67
+ .map { |key, value_hash| { key => value_hash[:value] } }
68
+ .inject(:merge) || {}
63
69
  end
64
70
  end
65
71
  end
@@ -1,4 +1,4 @@
1
- require 'action_controller'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Authlogic
4
4
  module ControllerAdapters
@@ -7,19 +7,18 @@ module Authlogic
7
7
  # Similar to how ActiveRecord has an adapter for MySQL, PostgreSQL, SQLite,
8
8
  # etc.
9
9
  class RailsAdapter < AbstractAdapter
10
- class AuthlogicLoadedTooLateError < StandardError; end
11
-
12
10
  def authenticate_with_http_basic(&block)
13
11
  controller.authenticate_with_http_basic(&block)
14
12
  end
15
13
 
14
+ # Returns a `ActionDispatch::Cookies::CookieJar`. See the AC guide
15
+ # http://guides.rubyonrails.org/action_controller_overview.html#cookies
16
16
  def cookies
17
17
  controller.send(:cookies)
18
18
  end
19
19
 
20
20
  def cookie_domain
21
- @cookie_domain_key ||= Rails::VERSION::STRING >= '2.3' ? :domain : :session_domain
22
- controller.request.session_options[@cookie_domain_key]
21
+ controller.request.session_options[:domain]
23
22
  end
24
23
 
25
24
  def request_content_type
@@ -30,36 +29,19 @@ module Authlogic
30
29
  # "activates" authlogic.
31
30
  module RailsImplementation
32
31
  def self.included(klass) # :nodoc:
33
- if defined?(::ApplicationController)
34
- raise AuthlogicLoadedTooLateError.new(
35
- <<-EOS.strip_heredoc
36
- Authlogic is trying to add a callback to ActionController::Base
37
- but ApplicationController has already been loaded, so the
38
- callback won't be copied into your application. Generally this
39
- is due to another gem or plugin requiring your
40
- ApplicationController prematurely, such as the
41
- resource_controller plugin. Please require Authlogic first,
42
- before these other gems / plugins.
43
- EOS
44
- )
45
- end
46
-
47
- # In Rails 4.0.2, the *_filter methods were renamed to *_action.
48
- if klass.respond_to? :prepend_before_action
49
- klass.prepend_before_action :activate_authlogic
50
- else
51
- klass.prepend_before_filter :activate_authlogic
52
- end
32
+ klass.prepend_before_action :activate_authlogic
53
33
  end
54
34
 
55
35
  private
56
36
 
57
- def activate_authlogic
58
- Authlogic::Session::Base.controller = RailsAdapter.new(self)
59
- end
37
+ def activate_authlogic
38
+ Authlogic::Session::Base.controller = RailsAdapter.new(self)
39
+ end
60
40
  end
61
41
  end
62
42
  end
63
43
  end
64
44
 
65
- ActionController::Base.send(:include, Authlogic::ControllerAdapters::RailsAdapter::RailsImplementation)
45
+ ActiveSupport.on_load(:action_controller) do
46
+ include Authlogic::ControllerAdapters::RailsAdapter::RailsImplementation
47
+ end
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Authlogic bridge for Sinatra
2
4
  module Authlogic
3
5
  module ControllerAdapters
4
6
  module SinatraAdapter
7
+ # Cookie management functions
5
8
  class Cookies
6
9
  attr_reader :request, :response
7
10
 
@@ -23,6 +26,7 @@ module Authlogic
23
26
  end
24
27
  end
25
28
 
29
+ # Thin wrapper around request and response.
26
30
  class Controller
27
31
  attr_reader :request, :response, :cookies
28
32
 
@@ -32,7 +36,7 @@ module Authlogic
32
36
  end
33
37
 
34
38
  def session
35
- env['rack.session']
39
+ env["rack.session"]
36
40
  end
37
41
 
38
42
  def method_missing(meth, *args, &block)
@@ -40,11 +44,13 @@ module Authlogic
40
44
  end
41
45
  end
42
46
 
47
+ # Sinatra controller adapter
43
48
  class Adapter < AbstractAdapter
44
49
  def cookie_domain
45
- env['SERVER_NAME']
50
+ env["SERVER_NAME"]
46
51
  end
47
52
 
53
+ # Mixed into `Sinatra::Base`
48
54
  module Implementation
49
55
  def self.included(klass)
50
56
  klass.send :before do
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Authlogic
4
+ # Represents the credentials *in* the cookie. The value of the cookie.
5
+ # This is primarily a data object. It doesn't interact with controllers.
6
+ # It doesn't know about eg. cookie expiration.
7
+ #
8
+ # @api private
9
+ class CookieCredentials
10
+ # @api private
11
+ class ParseError < RuntimeError
12
+ end
13
+
14
+ DELIMITER = "::"
15
+
16
+ attr_reader :persistence_token, :record_id, :remember_me_until
17
+
18
+ # @api private
19
+ # @param persistence_token [String]
20
+ # @param record_id [String, Numeric]
21
+ # @param remember_me_until [ActiveSupport::TimeWithZone]
22
+ def initialize(persistence_token, record_id, remember_me_until)
23
+ @persistence_token = persistence_token
24
+ @record_id = record_id
25
+ @remember_me_until = remember_me_until
26
+ end
27
+
28
+ class << self
29
+ # @api private
30
+ def parse(string)
31
+ parts = string.split(DELIMITER)
32
+ unless (1..3).cover?(parts.length)
33
+ raise ParseError, format("Expected 1..3 parts, got %d", parts.length)
34
+ end
35
+ new(parts[0], parts[1], parse_time(parts[2]))
36
+ end
37
+
38
+ private
39
+
40
+ # @api private
41
+ def parse_time(string)
42
+ return if string.nil?
43
+ ::Time.parse(string)
44
+ rescue ::ArgumentError => e
45
+ raise ParseError, format("Found cookie, cannot parse remember_me_until: #{e}")
46
+ end
47
+ end
48
+
49
+ # @api private
50
+ def remember_me?
51
+ !@remember_me_until.nil?
52
+ end
53
+
54
+ # @api private
55
+ def to_s
56
+ [
57
+ @persistence_token,
58
+ @record_id.to_s,
59
+ @remember_me_until&.iso8601
60
+ ].compact.join(DELIMITER)
61
+ end
62
+ end
63
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bcrypt"
2
4
 
3
5
  module Authlogic
@@ -16,10 +18,18 @@ module Authlogic
16
18
  # require "benchmark"
17
19
  #
18
20
  # Benchmark.bm(18) do |x|
19
- # x.report("BCrypt (cost = 10:") { 100.times { BCrypt::Password.create("mypass", :cost => 10) } }
20
- # x.report("BCrypt (cost = 4:") { 100.times { BCrypt::Password.create("mypass", :cost => 4) } }
21
- # x.report("Sha512:") { 100.times { Digest::SHA512.hexdigest("mypass") } }
22
- # x.report("Sha1:") { 100.times { Digest::SHA1.hexdigest("mypass") } }
21
+ # x.report("BCrypt (cost = 10:") {
22
+ # 100.times { BCrypt::Password.create("mypass", :cost => 10) }
23
+ # }
24
+ # x.report("BCrypt (cost = 4:") {
25
+ # 100.times { BCrypt::Password.create("mypass", :cost => 4) }
26
+ # }
27
+ # x.report("Sha512:") {
28
+ # 100.times { Digest::SHA512.hexdigest("mypass") }
29
+ # }
30
+ # x.report("Sha1:") {
31
+ # 100.times { Digest::SHA1.hexdigest("mypass") }
32
+ # }
23
33
  # end
24
34
  #
25
35
  # user system total real
@@ -56,17 +66,15 @@ module Authlogic
56
66
 
57
67
  def cost=(val)
58
68
  if val < ::BCrypt::Engine::MIN_COST
59
- raise ArgumentError.new(
60
- "Authlogic's bcrypt cost cannot be set below the engine's " \
69
+ raise ArgumentError, "Authlogic's bcrypt cost cannot be set below the engine's " \
61
70
  "min cost (#{::BCrypt::Engine::MIN_COST})"
62
- )
63
71
  end
64
72
  @cost = val
65
73
  end
66
74
 
67
75
  # Creates a BCrypt hash for the password passed.
68
76
  def encrypt(*tokens)
69
- ::BCrypt::Password.create(join_tokens(tokens), :cost => cost)
77
+ ::BCrypt::Password.create(join_tokens(tokens), cost: cost)
70
78
  end
71
79
 
72
80
  # Does the hash match the tokens? Uses the same tokens that were used to
@@ -90,17 +98,15 @@ module Authlogic
90
98
 
91
99
  private
92
100
 
93
- def join_tokens(tokens)
94
- tokens.flatten.join
95
- end
101
+ def join_tokens(tokens)
102
+ tokens.flatten.join
103
+ end
96
104
 
97
- def new_from_hash(hash)
98
- begin
99
- ::BCrypt::Password.new(hash)
100
- rescue ::BCrypt::Errors::InvalidHash
101
- return nil
102
- end
103
- end
105
+ def new_from_hash(hash)
106
+ ::BCrypt::Password.new(hash)
107
+ rescue ::BCrypt::Errors::InvalidHash
108
+ nil
109
+ end
104
110
  end
105
111
  end
106
112
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/md5"
4
+
5
+ module Authlogic
6
+ module CryptoProviders
7
+ class MD5
8
+ # A poor choice. There are known attacks against this algorithm.
9
+ class V2
10
+ class << self
11
+ attr_accessor :join_token
12
+
13
+ # The number of times to loop through the encryption.
14
+ def stretches
15
+ @stretches ||= 1
16
+ end
17
+ attr_writer :stretches
18
+
19
+ # Turns your raw password into a MD5 hash.
20
+ def encrypt(*tokens)
21
+ digest = tokens.flatten.join(join_token)
22
+ stretches.times { digest = Digest::MD5.digest(digest) }
23
+ digest.unpack("H*")[0]
24
+ end
25
+
26
+ # Does the crypted password match the tokens? Uses the same tokens that
27
+ # were used to encrypt.
28
+ def matches?(crypted, *tokens)
29
+ encrypt(*tokens) == crypted
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,13 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "digest/md5"
2
4
 
3
5
  module Authlogic
4
6
  module CryptoProviders
5
- # This class was made for the users transitioning from md5 based systems.
6
- # I highly discourage using this crypto provider as it superbly inferior
7
- # to your other options.
8
- #
9
- # Please use any other provider offered by Authlogic.
7
+ # A poor choice. There are known attacks against this algorithm.
10
8
  class MD5
9
+ # V2 hashes the digest bytes in repeated stretches instead of hex characters.
10
+ autoload :V2, File.join(__dir__, "md5", "v2")
11
+
11
12
  class << self
12
13
  attr_accessor :join_token
13
14
 
@@ -24,7 +25,8 @@ module Authlogic
24
25
  digest
25
26
  end
26
27
 
27
- # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
28
+ # Does the crypted password match the tokens? Uses the same tokens that
29
+ # were used to encrypt.
28
30
  def matches?(crypted, *tokens)
29
31
  encrypt(*tokens) == crypted
30
32
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "scrypt"
2
4
 
3
5
  module Authlogic
@@ -19,7 +21,13 @@ module Authlogic
19
21
  # end
20
22
  class SCrypt
21
23
  class << self
22
- DEFAULTS = { :key_len => 32, :salt_size => 8, :max_time => 0.2, :max_mem => 1024 * 1024, :max_memfrac => 0.5 }
24
+ DEFAULTS = {
25
+ key_len: 32,
26
+ salt_size: 8,
27
+ max_time: 0.2,
28
+ max_mem: 1024 * 1024,
29
+ max_memfrac: 0.5
30
+ }.freeze
23
31
 
24
32
  attr_writer :key_len, :salt_size, :max_time, :max_mem, :max_memfrac
25
33
  # Key length - length in bytes of generated key, from 16 to 512.
@@ -42,7 +50,8 @@ module Authlogic
42
50
  @max_mem ||= DEFAULTS[:max_mem]
43
51
  end
44
52
 
45
- # Max memory fraction - maximum memory out of all available. Always greater than zero and <= 0.5.
53
+ # Max memory fraction - maximum memory out of all available. Always
54
+ # greater than zero and <= 0.5.
46
55
  def max_memfrac
47
56
  @max_memfrac ||= DEFAULTS[:max_memfrac]
48
57
  end
@@ -51,11 +60,11 @@ module Authlogic
51
60
  def encrypt(*tokens)
52
61
  ::SCrypt::Password.create(
53
62
  join_tokens(tokens),
54
- :key_len => key_len,
55
- :salt_size => salt_size,
56
- :max_mem => max_mem,
57
- :max_memfrac => max_memfrac,
58
- :max_time => max_time
63
+ key_len: key_len,
64
+ salt_size: salt_size,
65
+ max_mem: max_mem,
66
+ max_memfrac: max_memfrac,
67
+ max_time: max_time
59
68
  )
60
69
  end
61
70
 
@@ -68,17 +77,15 @@ module Authlogic
68
77
 
69
78
  private
70
79
 
71
- def join_tokens(tokens)
72
- tokens.flatten.join
73
- end
80
+ def join_tokens(tokens)
81
+ tokens.flatten.join
82
+ end
74
83
 
75
- def new_from_hash(hash)
76
- begin
77
- ::SCrypt::Password.new(hash)
78
- rescue ::SCrypt::Errors::InvalidHash
79
- return nil
80
- end
81
- end
84
+ def new_from_hash(hash)
85
+ ::SCrypt::Password.new(hash)
86
+ rescue ::SCrypt::Errors::InvalidHash
87
+ nil
88
+ end
82
89
  end
83
90
  end
84
91
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/sha1"
4
+
5
+ module Authlogic
6
+ module CryptoProviders
7
+ class Sha1
8
+ # A poor choice. There are known attacks against this algorithm.
9
+ class V2
10
+ class << self
11
+ def join_token
12
+ @join_token ||= "--"
13
+ end
14
+ attr_writer :join_token
15
+
16
+ # The number of times to loop through the encryption.
17
+ def stretches
18
+ @stretches ||= 10
19
+ end
20
+ attr_writer :stretches
21
+
22
+ # Turns your raw password into a Sha1 hash.
23
+ def encrypt(*tokens)
24
+ tokens = tokens.flatten
25
+ digest = tokens.shift
26
+ stretches.times do
27
+ digest = Digest::SHA1.digest([digest, *tokens].join(join_token))
28
+ end
29
+ digest.unpack("H*")[0]
30
+ end
31
+
32
+ # Does the crypted password match the tokens? Uses the same tokens that
33
+ # were used to encrypt.
34
+ def matches?(crypted, *tokens)
35
+ encrypt(*tokens) == crypted
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,17 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "digest/sha1"
2
4
 
3
5
  module Authlogic
4
6
  module CryptoProviders
5
- # This class was made for the users transitioning from restful_authentication. I highly discourage using this
6
- # crypto provider as it is far inferior to your other options. Please use any other provider offered by Authlogic.
7
+ # A poor choice. There are known attacks against this algorithm.
7
8
  class Sha1
9
+ # V2 hashes the digest bytes in repeated stretches instead of hex characters.
10
+ autoload :V2, File.join(__dir__, "sha1", "v2")
11
+
8
12
  class << self
9
13
  def join_token
10
14
  @join_token ||= "--"
11
15
  end
12
16
  attr_writer :join_token
13
17
 
14
- # The number of times to loop through the encryption. This is ten because that is what restful_authentication defaults to.
18
+ # The number of times to loop through the encryption.
15
19
  def stretches
16
20
  @stretches ||= 10
17
21
  end
@@ -21,11 +25,14 @@ module Authlogic
21
25
  def encrypt(*tokens)
22
26
  tokens = tokens.flatten
23
27
  digest = tokens.shift
24
- stretches.times { digest = Digest::SHA1.hexdigest([digest, *tokens].join(join_token)) }
28
+ stretches.times do
29
+ digest = Digest::SHA1.hexdigest([digest, *tokens].join(join_token))
30
+ end
25
31
  digest
26
32
  end
27
33
 
28
- # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
34
+ # Does the crypted password match the tokens? Uses the same tokens that
35
+ # were used to encrypt.
29
36
  def matches?(crypted, *tokens)
30
37
  encrypt(*tokens) == crypted
31
38
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/sha2"
4
+
5
+ module Authlogic
6
+ # The acts_as_authentic method has a crypto_provider option. This allows you
7
+ # to use any type of encryption you like. Just create a class with a class
8
+ # level encrypt and matches? method. See example below.
9
+ #
10
+ # === Example
11
+ #
12
+ # class MyAwesomeEncryptionMethod
13
+ # def self.encrypt(*tokens)
14
+ # # the tokens passed will be an array of objects, what type of object
15
+ # # is irrelevant, just do what you need to do with them and return a
16
+ # # single encrypted string. for example, you will most likely join all
17
+ # # of the objects into a single string and then encrypt that string
18
+ # end
19
+ #
20
+ # def self.matches?(crypted, *tokens)
21
+ # # return true if the crypted string matches the tokens. Depending on
22
+ # # your algorithm you might decrypt the string then compare it to the
23
+ # # token, or you might encrypt the tokens and make sure it matches the
24
+ # # crypted string, its up to you.
25
+ # end
26
+ # end
27
+ module CryptoProviders
28
+ class Sha256
29
+ # = Sha256
30
+ #
31
+ # Uses the Sha256 hash algorithm to encrypt passwords.
32
+ class V2
33
+ class << self
34
+ attr_accessor :join_token
35
+
36
+ # The number of times to loop through the encryption.
37
+ def stretches
38
+ @stretches ||= 20
39
+ end
40
+ attr_writer :stretches
41
+
42
+ # Turns your raw password into a Sha256 hash.
43
+ def encrypt(*tokens)
44
+ digest = tokens.flatten.join(join_token)
45
+ stretches.times { digest = Digest::SHA256.digest(digest) }
46
+ digest.unpack("H*")[0]
47
+ end
48
+
49
+ # Does the crypted password match the tokens? Uses the same tokens that
50
+ # were used to encrypt.
51
+ def matches?(crypted, *tokens)
52
+ encrypt(*tokens) == crypted
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end