devise-bootstrap 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +31 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +1 -0
  7. data/app/controllers/devise/confirmations_controller.rb +47 -0
  8. data/app/controllers/devise/omniauth_callbacks_controller.rb +30 -0
  9. data/app/controllers/devise/passwords_controller.rb +70 -0
  10. data/app/controllers/devise/registrations_controller.rb +137 -0
  11. data/app/controllers/devise/sessions_controller.rb +53 -0
  12. data/app/controllers/devise/unlocks_controller.rb +46 -0
  13. data/app/controllers/devise_controller.rb +176 -0
  14. data/app/helpers/devise_helper.rb +25 -0
  15. data/app/mailers/devise/mailer.rb +20 -0
  16. data/app/views/devise/confirmations/new.html.erb +12 -0
  17. data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  18. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  19. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  20. data/app/views/devise/passwords/edit.html.erb +16 -0
  21. data/app/views/devise/passwords/new.html.erb +12 -0
  22. data/app/views/devise/registrations/edit.html.erb +29 -0
  23. data/app/views/devise/registrations/new.html.erb +18 -0
  24. data/app/views/devise/sessions/new.html.erb +17 -0
  25. data/app/views/devise/shared/_links.erb +25 -0
  26. data/app/views/devise/unlocks/new.html.erb +12 -0
  27. data/config/locales/en.yml +59 -0
  28. data/devise-bootstrap.gemspec +30 -0
  29. data/gemfiles/Gemfile.rails-3.2-stable +29 -0
  30. data/gemfiles/Gemfile.rails-4.0-stable +29 -0
  31. data/gemfiles/Gemfile.rails-head +29 -0
  32. data/lib/devise/bootstrap.rb +7 -0
  33. data/lib/devise/bootstrap/version.rb +5 -0
  34. data/lib/devise/devise.rb +491 -0
  35. data/lib/devise/devise/controllers/helpers.rb +213 -0
  36. data/lib/devise/devise/controllers/rememberable.rb +47 -0
  37. data/lib/devise/devise/controllers/scoped_views.rb +17 -0
  38. data/lib/devise/devise/controllers/sign_in_out.rb +103 -0
  39. data/lib/devise/devise/controllers/store_location.rb +50 -0
  40. data/lib/devise/devise/controllers/url_helpers.rb +67 -0
  41. data/lib/devise/devise/delegator.rb +16 -0
  42. data/lib/devise/devise/failure_app.rb +205 -0
  43. data/lib/devise/devise/hooks/activatable.rb +11 -0
  44. data/lib/devise/devise/hooks/csrf_cleaner.rb +5 -0
  45. data/lib/devise/devise/hooks/forgetable.rb +9 -0
  46. data/lib/devise/devise/hooks/lockable.rb +7 -0
  47. data/lib/devise/devise/hooks/proxy.rb +21 -0
  48. data/lib/devise/devise/hooks/rememberable.rb +7 -0
  49. data/lib/devise/devise/hooks/timeoutable.rb +28 -0
  50. data/lib/devise/devise/hooks/trackable.rb +9 -0
  51. data/lib/devise/devise/mailers/helpers.rb +90 -0
  52. data/lib/devise/devise/mapping.rb +172 -0
  53. data/lib/devise/devise/models.rb +119 -0
  54. data/lib/devise/devise/models/authenticatable.rb +284 -0
  55. data/lib/devise/devise/models/confirmable.rb +295 -0
  56. data/lib/devise/devise/models/database_authenticatable.rb +164 -0
  57. data/lib/devise/devise/models/lockable.rb +196 -0
  58. data/lib/devise/devise/models/omniauthable.rb +27 -0
  59. data/lib/devise/devise/models/recoverable.rb +131 -0
  60. data/lib/devise/devise/models/registerable.rb +25 -0
  61. data/lib/devise/devise/models/rememberable.rb +129 -0
  62. data/lib/devise/devise/models/timeoutable.rb +49 -0
  63. data/lib/devise/devise/models/trackable.rb +35 -0
  64. data/lib/devise/devise/models/validatable.rb +66 -0
  65. data/lib/devise/devise/modules.rb +28 -0
  66. data/lib/devise/devise/omniauth.rb +28 -0
  67. data/lib/devise/devise/omniauth/config.rb +45 -0
  68. data/lib/devise/devise/omniauth/url_helpers.rb +18 -0
  69. data/lib/devise/devise/orm/active_record.rb +3 -0
  70. data/lib/devise/devise/orm/mongoid.rb +3 -0
  71. data/lib/devise/devise/parameter_filter.rb +40 -0
  72. data/lib/devise/devise/parameter_sanitizer.rb +99 -0
  73. data/lib/devise/devise/rails.rb +56 -0
  74. data/lib/devise/devise/rails/routes.rb +496 -0
  75. data/lib/devise/devise/rails/warden_compat.rb +22 -0
  76. data/lib/devise/devise/strategies/authenticatable.rb +167 -0
  77. data/lib/devise/devise/strategies/base.rb +20 -0
  78. data/lib/devise/devise/strategies/database_authenticatable.rb +23 -0
  79. data/lib/devise/devise/strategies/rememberable.rb +55 -0
  80. data/lib/devise/devise/test_helpers.rb +132 -0
  81. data/lib/devise/devise/time_inflector.rb +14 -0
  82. data/lib/devise/devise/token_generator.rb +70 -0
  83. data/lib/devise/devise/version.rb +3 -0
  84. data/lib/devise/generators/active_record/devise_generator.rb +73 -0
  85. data/lib/devise/generators/active_record/templates/migration.rb +18 -0
  86. data/lib/devise/generators/active_record/templates/migration_existing.rb +25 -0
  87. data/lib/devise/generators/devise/devise_generator.rb +26 -0
  88. data/lib/devise/generators/devise/install_generator.rb +29 -0
  89. data/lib/devise/generators/devise/orm_helpers.rb +51 -0
  90. data/lib/devise/generators/devise/views_generator.rb +135 -0
  91. data/lib/devise/generators/mongoid/devise_generator.rb +55 -0
  92. data/lib/devise/generators/templates/README +35 -0
  93. data/lib/devise/generators/templates/devise.rb +260 -0
  94. data/lib/devise/generators/templates/markerb/confirmation_instructions.markerb +5 -0
  95. data/lib/devise/generators/templates/markerb/reset_password_instructions.markerb +8 -0
  96. data/lib/devise/generators/templates/markerb/unlock_instructions.markerb +7 -0
  97. data/lib/devise/generators/templates/simple_form_for/confirmations/new.html.erb +16 -0
  98. data/lib/devise/generators/templates/simple_form_for/passwords/edit.html.erb +19 -0
  99. data/lib/devise/generators/templates/simple_form_for/passwords/new.html.erb +15 -0
  100. data/lib/devise/generators/templates/simple_form_for/registrations/edit.html.erb +27 -0
  101. data/lib/devise/generators/templates/simple_form_for/registrations/new.html.erb +17 -0
  102. data/lib/devise/generators/templates/simple_form_for/sessions/new.html.erb +15 -0
  103. data/lib/devise/generators/templates/simple_form_for/unlocks/new.html.erb +16 -0
  104. metadata +250 -0
@@ -0,0 +1,22 @@
1
+ module Warden::Mixins::Common
2
+ def request
3
+ @request ||= ActionDispatch::Request.new(env)
4
+ end
5
+
6
+ # Deprecate: Remove this check once we move to Rails 4 only.
7
+ NULL_STORE =
8
+ defined?(ActionController::RequestForgeryProtection::ProtectionMethods::NullSession::NullSessionHash) ?
9
+ ActionController::RequestForgeryProtection::ProtectionMethods::NullSession::NullSessionHash : nil
10
+
11
+ def reset_session!
12
+ # Calling reset_session on NULL_STORE causes it fail.
13
+ # This is a bug that needs to be fixed in Rails.
14
+ unless NULL_STORE && request.session.is_a?(NULL_STORE)
15
+ request.reset_session
16
+ end
17
+ end
18
+
19
+ def cookies
20
+ request.cookie_jar
21
+ end
22
+ end
@@ -0,0 +1,167 @@
1
+ require 'devise/strategies/base'
2
+
3
+ module Devise
4
+ module Strategies
5
+ # This strategy should be used as basis for authentication strategies. It retrieves
6
+ # parameters both from params or from http authorization headers. See database_authenticatable
7
+ # for an example.
8
+ class Authenticatable < Base
9
+ attr_accessor :authentication_hash, :authentication_type, :password
10
+
11
+ def store?
12
+ super && !mapping.to.skip_session_storage.include?(authentication_type)
13
+ end
14
+
15
+ def valid?
16
+ valid_for_params_auth? || valid_for_http_auth?
17
+ end
18
+
19
+ private
20
+
21
+ # Receives a resource and check if it is valid by calling valid_for_authentication?
22
+ # An optional block that will be triggered while validating can be optionally
23
+ # given as parameter. Check Devise::Models::Authenticable.valid_for_authentication?
24
+ # for more information.
25
+ #
26
+ # In case the resource can't be validated, it will fail with the given
27
+ # unauthenticated_message.
28
+ def validate(resource, &block)
29
+ result = resource && resource.valid_for_authentication?(&block)
30
+
31
+ if result
32
+ decorate(resource)
33
+ true
34
+ else
35
+ if resource
36
+ fail!(resource.unauthenticated_message)
37
+ end
38
+ false
39
+ end
40
+ end
41
+
42
+ # Get values from params and set in the resource.
43
+ def decorate(resource)
44
+ resource.remember_me = remember_me? if resource.respond_to?(:remember_me=)
45
+ end
46
+
47
+ # Should this resource be marked to be remembered?
48
+ def remember_me?
49
+ valid_params? && Devise::TRUE_VALUES.include?(params_auth_hash[:remember_me])
50
+ end
51
+
52
+ # Check if this is a valid strategy for http authentication by:
53
+ #
54
+ # * Validating if the model allows params authentication;
55
+ # * If any of the authorization headers were sent;
56
+ # * If all authentication keys are present;
57
+ #
58
+ def valid_for_http_auth?
59
+ http_authenticatable? && request.authorization && with_authentication_hash(:http_auth, http_auth_hash)
60
+ end
61
+
62
+ # Check if this is a valid strategy for params authentication by:
63
+ #
64
+ # * Validating if the model allows params authentication;
65
+ # * If the request hits the sessions controller through POST;
66
+ # * If the params[scope] returns a hash with credentials;
67
+ # * If all authentication keys are present;
68
+ #
69
+ def valid_for_params_auth?
70
+ params_authenticatable? && valid_params_request? &&
71
+ valid_params? && with_authentication_hash(:params_auth, params_auth_hash)
72
+ end
73
+
74
+ # Check if the model accepts this strategy as http authenticatable.
75
+ def http_authenticatable?
76
+ mapping.to.http_authenticatable?(authenticatable_name)
77
+ end
78
+
79
+ # Check if the model accepts this strategy as params authenticatable.
80
+ def params_authenticatable?
81
+ mapping.to.params_authenticatable?(authenticatable_name)
82
+ end
83
+
84
+ # Extract the appropriate subhash for authentication from params.
85
+ def params_auth_hash
86
+ params[scope]
87
+ end
88
+
89
+ # Extract a hash with attributes:values from the http params.
90
+ def http_auth_hash
91
+ keys = [http_authentication_key, :password]
92
+ Hash[*keys.zip(decode_credentials).flatten]
93
+ end
94
+
95
+ # By default, a request is valid if the controller set the proper env variable.
96
+ def valid_params_request?
97
+ !!env["devise.allow_params_authentication"]
98
+ end
99
+
100
+ # If the request is valid, finally check if params_auth_hash returns a hash.
101
+ def valid_params?
102
+ params_auth_hash.is_a?(Hash)
103
+ end
104
+
105
+ # Check if password is present.
106
+ def valid_password?
107
+ password.present?
108
+ end
109
+
110
+ # Helper to decode credentials from HTTP.
111
+ def decode_credentials
112
+ return [] unless request.authorization && request.authorization =~ /^Basic (.*)/m
113
+ Base64.decode64($1).split(/:/, 2)
114
+ end
115
+
116
+ # Sets the authentication hash and the password from params_auth_hash or http_auth_hash.
117
+ def with_authentication_hash(auth_type, auth_values)
118
+ self.authentication_hash, self.authentication_type = {}, auth_type
119
+ self.password = auth_values[:password]
120
+
121
+ parse_authentication_key_values(auth_values, authentication_keys) &&
122
+ parse_authentication_key_values(request_values, request_keys)
123
+ end
124
+
125
+ def authentication_keys
126
+ @authentication_keys ||= mapping.to.authentication_keys
127
+ end
128
+
129
+ def http_authentication_key
130
+ @http_authentication_key ||= mapping.to.http_authentication_key || case authentication_keys
131
+ when Array then authentication_keys.first
132
+ when Hash then authentication_keys.keys.first
133
+ end
134
+ end
135
+
136
+ def request_keys
137
+ @request_keys ||= mapping.to.request_keys
138
+ end
139
+
140
+ def request_values
141
+ keys = request_keys.respond_to?(:keys) ? request_keys.keys : request_keys
142
+ values = keys.map { |k| self.request.send(k) }
143
+ Hash[keys.zip(values)]
144
+ end
145
+
146
+ def parse_authentication_key_values(hash, keys)
147
+ keys.each do |key, enforce|
148
+ value = hash[key].presence
149
+ if value
150
+ self.authentication_hash[key] = value
151
+ else
152
+ return false unless enforce == false
153
+ end
154
+ end
155
+ true
156
+ end
157
+
158
+ # Holds the authenticatable name for this class. Devise::Strategies::DatabaseAuthenticatable
159
+ # becomes simply :database.
160
+ def authenticatable_name
161
+ @authenticatable_name ||=
162
+ ActiveSupport::Inflector.underscore(self.class.name.split("::").last).
163
+ sub("_authenticatable", "").to_sym
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,20 @@
1
+ module Devise
2
+ module Strategies
3
+ # Base strategy for Devise. Responsible for verifying correct scope and mapping.
4
+ class Base < ::Warden::Strategies::Base
5
+ # Whenever CSRF cannot be verified, we turn off any kind of storage
6
+ def store?
7
+ !env["devise.skip_storage"]
8
+ end
9
+
10
+ # Checks if a valid scope was given for devise and find mapping based on this scope.
11
+ def mapping
12
+ @mapping ||= begin
13
+ mapping = Devise.mappings[scope]
14
+ raise "Could not find mapping for #{scope}" unless mapping
15
+ mapping
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ require 'devise/strategies/authenticatable'
2
+
3
+ module Devise
4
+ module Strategies
5
+ # Default strategy for signing in a user, based on their email and password in the database.
6
+ class DatabaseAuthenticatable < Authenticatable
7
+ def authenticate!
8
+ resource = valid_password? && mapping.to.find_for_database_authentication(authentication_hash)
9
+ encrypted = false
10
+
11
+ if validate(resource){ encrypted = true; resource.valid_password?(password) }
12
+ resource.after_database_authentication
13
+ success!(resource)
14
+ end
15
+
16
+ mapping.to.new.password = password if !encrypted && Devise.paranoid
17
+ fail(:not_found_in_database) unless resource
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ Warden::Strategies.add(:database_authenticatable, Devise::Strategies::DatabaseAuthenticatable)
@@ -0,0 +1,55 @@
1
+ require 'devise/strategies/authenticatable'
2
+
3
+ module Devise
4
+ module Strategies
5
+ # Remember the user through the remember token. This strategy is responsible
6
+ # to verify whether there is a cookie with the remember token, and to
7
+ # recreate the user from this cookie if it exists. Must be called *before*
8
+ # authenticatable.
9
+ class Rememberable < Authenticatable
10
+ # A valid strategy for rememberable needs a remember token in the cookies.
11
+ def valid?
12
+ @remember_cookie = nil
13
+ remember_cookie.present?
14
+ end
15
+
16
+ # To authenticate a user we deserialize the cookie and attempt finding
17
+ # the record in the database. If the attempt fails, we pass to another
18
+ # strategy handle the authentication.
19
+ def authenticate!
20
+ resource = mapping.to.serialize_from_cookie(*remember_cookie)
21
+
22
+ unless resource
23
+ cookies.delete(remember_key)
24
+ return pass
25
+ end
26
+
27
+ if validate(resource)
28
+ success!(resource)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def decorate(resource)
35
+ super
36
+ resource.extend_remember_period = mapping.to.extend_remember_period if resource.respond_to?(:extend_remember_period=)
37
+ end
38
+
39
+ def remember_me?
40
+ true
41
+ end
42
+
43
+ def remember_key
44
+ mapping.to.rememberable_options.fetch(:key, "remember_#{scope}_token")
45
+ end
46
+
47
+ def remember_cookie
48
+ @remember_cookie ||= cookies.signed[remember_key]
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+
55
+ Warden::Strategies.add(:rememberable, Devise::Strategies::Rememberable)
@@ -0,0 +1,132 @@
1
+ module Devise
2
+ # Devise::TestHelpers provides a facility to test controllers in isolation
3
+ # when using ActionController::TestCase allowing you to quickly sign_in or
4
+ # sign_out a user. Do not use Devise::TestHelpers in integration tests.
5
+ #
6
+ # Notice you should not test Warden specific behavior (like Warden callbacks)
7
+ # using Devise::TestHelpers since it is a stub of the actual behavior. Such
8
+ # callbacks should be tested in your integration suite instead.
9
+ module TestHelpers
10
+ def self.included(base)
11
+ base.class_eval do
12
+ setup :setup_controller_for_warden, :warden if respond_to?(:setup)
13
+ end
14
+ end
15
+
16
+ # Override process to consider warden.
17
+ def process(*)
18
+ # Make sure we always return @response, a la ActionController::TestCase::Behaviour#process, even if warden interrupts
19
+ _catch_warden { super } || @response
20
+ end
21
+
22
+ # We need to setup the environment variables and the response in the controller.
23
+ def setup_controller_for_warden #:nodoc:
24
+ @request.env['action_controller.instance'] = @controller
25
+ end
26
+
27
+ # Quick access to Warden::Proxy.
28
+ def warden #:nodoc:
29
+ @warden ||= begin
30
+ manager = Warden::Manager.new(nil) do |config|
31
+ config.merge! Devise.warden_config
32
+ end
33
+ @request.env['warden'] = Warden::Proxy.new(@request.env, manager)
34
+ end
35
+ end
36
+
37
+ # sign_in a given resource by storing its keys in the session.
38
+ # This method bypass any warden authentication callback.
39
+ #
40
+ # Examples:
41
+ #
42
+ # sign_in :user, @user # sign_in(scope, resource)
43
+ # sign_in @user # sign_in(resource)
44
+ #
45
+ def sign_in(resource_or_scope, resource=nil)
46
+ scope ||= Devise::Mapping.find_scope!(resource_or_scope)
47
+ resource ||= resource_or_scope
48
+ warden.instance_variable_get(:@users).delete(scope)
49
+ warden.session_serializer.store(resource, scope)
50
+ end
51
+
52
+ # Sign out a given resource or scope by calling logout on Warden.
53
+ # This method bypass any warden logout callback.
54
+ #
55
+ # Examples:
56
+ #
57
+ # sign_out :user # sign_out(scope)
58
+ # sign_out @user # sign_out(resource)
59
+ #
60
+ def sign_out(resource_or_scope)
61
+ scope = Devise::Mapping.find_scope!(resource_or_scope)
62
+ @controller.instance_variable_set(:"@current_#{scope}", nil)
63
+ user = warden.instance_variable_get(:@users).delete(scope)
64
+ warden.session_serializer.delete(scope, user)
65
+ end
66
+
67
+ protected
68
+
69
+ # Catch warden continuations and handle like the middleware would.
70
+ # Returns nil when interrupted, otherwise the normal result of the block.
71
+ def _catch_warden(&block)
72
+ result = catch(:warden, &block)
73
+
74
+ env = @controller.request.env
75
+
76
+ result ||= {}
77
+
78
+ # Set the response. In production, the rack result is returned
79
+ # from Warden::Manager#call, which the following is modelled on.
80
+ case result
81
+ when Array
82
+ if result.first == 401 && intercept_401?(env) # does this happen during testing?
83
+ _process_unauthenticated(env)
84
+ else
85
+ result
86
+ end
87
+ when Hash
88
+ _process_unauthenticated(env, result)
89
+ else
90
+ result
91
+ end
92
+ end
93
+
94
+ def _process_unauthenticated(env, options = {})
95
+ options[:action] ||= :unauthenticated
96
+ proxy = env['warden']
97
+ result = options[:result] || proxy.result
98
+
99
+ ret = case result
100
+ when :redirect
101
+ body = proxy.message || "You are being redirected to #{proxy.headers['Location']}"
102
+ [proxy.status, proxy.headers, [body]]
103
+ when :custom
104
+ proxy.custom_response
105
+ else
106
+ env["PATH_INFO"] = "/#{options[:action]}"
107
+ env["warden.options"] = options
108
+ Warden::Manager._run_callbacks(:before_failure, env, options)
109
+
110
+ status, headers, response = Devise.warden_config[:failure_app].call(env).to_a
111
+ @controller.response.headers.merge!(headers)
112
+ @controller.send :render, status: status, text: response.body,
113
+ content_type: headers["Content-Type"], location: headers["Location"]
114
+ nil # causes process return @response
115
+ end
116
+
117
+ # ensure that the controller response is set up. In production, this is
118
+ # not necessary since warden returns the results to rack. However, at
119
+ # testing time, we want the response to be available to the testing
120
+ # framework to verify what would be returned to rack.
121
+ if ret.is_a?(Array)
122
+ # ensure the controller response is set to our response.
123
+ @controller.response ||= @response
124
+ @response.status = ret.first
125
+ @response.headers = ret.second
126
+ @response.body = ret.third
127
+ end
128
+
129
+ ret
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,14 @@
1
+ require "active_support/core_ext/module/delegation"
2
+
3
+ module Devise
4
+ class TimeInflector
5
+ include ActionView::Helpers::DateHelper
6
+
7
+ class << self
8
+ attr_reader :instance
9
+ delegate :time_ago_in_words, to: :instance
10
+ end
11
+
12
+ @instance = new
13
+ end
14
+ end
@@ -0,0 +1,70 @@
1
+ # Deprecate: Copied verbatim from Rails source, remove once we move to Rails 4 only.
2
+ require 'thread_safe'
3
+ require 'openssl'
4
+ require 'securerandom'
5
+
6
+ module Devise
7
+ class TokenGenerator
8
+ def initialize(key_generator, digest="SHA256")
9
+ @key_generator = key_generator
10
+ @digest = digest
11
+ end
12
+
13
+ def digest(klass, column, value)
14
+ value.present? && OpenSSL::HMAC.hexdigest(@digest, key_for(column), value.to_s)
15
+ end
16
+
17
+ def generate(klass, column)
18
+ key = key_for(column)
19
+
20
+ loop do
21
+ raw = Devise.friendly_token
22
+ enc = OpenSSL::HMAC.hexdigest(@digest, key, raw)
23
+ break [raw, enc] unless klass.to_adapter.find_first({ column => enc })
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def key_for(column)
30
+ @key_generator.generate_key("Devise #{column}")
31
+ end
32
+ end
33
+
34
+ # KeyGenerator is a simple wrapper around OpenSSL's implementation of PBKDF2
35
+ # It can be used to derive a number of keys for various purposes from a given secret.
36
+ # This lets Rails applications have a single secure secret, but avoid reusing that
37
+ # key in multiple incompatible contexts.
38
+ class KeyGenerator
39
+ def initialize(secret, options = {})
40
+ @secret = secret
41
+ # The default iterations are higher than required for our key derivation uses
42
+ # on the off chance someone uses this for password storage
43
+ @iterations = options[:iterations] || 2**16
44
+ end
45
+
46
+ # Returns a derived key suitable for use. The default key_size is chosen
47
+ # to be compatible with the default settings of ActiveSupport::MessageVerifier.
48
+ # i.e. OpenSSL::Digest::SHA1#block_length
49
+ def generate_key(salt, key_size=64)
50
+ OpenSSL::PKCS5.pbkdf2_hmac_sha1(@secret, salt, @iterations, key_size)
51
+ end
52
+ end
53
+
54
+ # CachingKeyGenerator is a wrapper around KeyGenerator which allows users to avoid
55
+ # re-executing the key generation process when it's called using the same salt and
56
+ # key_size
57
+ class CachingKeyGenerator
58
+ def initialize(key_generator)
59
+ @key_generator = key_generator
60
+ @cache_keys = ThreadSafe::Cache.new
61
+ end
62
+
63
+ # Returns a derived key suitable for use. The default key_size is chosen
64
+ # to be compatible with the default settings of ActiveSupport::MessageVerifier.
65
+ # i.e. OpenSSL::Digest::SHA1#block_length
66
+ def generate_key(salt, key_size=64)
67
+ @cache_keys["#{salt}#{key_size}"] ||= @key_generator.generate_key(salt, key_size)
68
+ end
69
+ end
70
+ end