upstream-devise 2.1.0.rc

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 (215) hide show
  1. data/.gitignore +10 -0
  2. data/.travis.yml +15 -0
  3. data/CHANGELOG.rdoc +846 -0
  4. data/Gemfile +35 -0
  5. data/Gemfile.lock +165 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +384 -0
  8. data/Rakefile +34 -0
  9. data/app/controllers/devise/confirmations_controller.rb +43 -0
  10. data/app/controllers/devise/omniauth_callbacks_controller.rb +24 -0
  11. data/app/controllers/devise/passwords_controller.rb +47 -0
  12. data/app/controllers/devise/registrations_controller.rb +107 -0
  13. data/app/controllers/devise/sessions_controller.rb +49 -0
  14. data/app/controllers/devise/unlocks_controller.rb +44 -0
  15. data/app/controllers/devise_controller.rb +177 -0
  16. data/app/helpers/devise_helper.rb +25 -0
  17. data/app/mailers/devise/mailer.rb +15 -0
  18. data/app/views/devise/_links.erb +3 -0
  19. data/app/views/devise/confirmations/new.html.erb +12 -0
  20. data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  21. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  22. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  23. data/app/views/devise/passwords/edit.html.erb +16 -0
  24. data/app/views/devise/passwords/new.html.erb +12 -0
  25. data/app/views/devise/registrations/edit.html.erb +25 -0
  26. data/app/views/devise/registrations/new.html.erb +18 -0
  27. data/app/views/devise/sessions/new.html.erb +17 -0
  28. data/app/views/devise/shared/_links.erb +25 -0
  29. data/app/views/devise/unlocks/new.html.erb +12 -0
  30. data/config/locales/en.yml +57 -0
  31. data/devise.gemspec +25 -0
  32. data/gemfiles/Gemfile.rails-3.1.x +35 -0
  33. data/gemfiles/Gemfile.rails-3.1.x.lock +167 -0
  34. data/lib/devise.rb +455 -0
  35. data/lib/devise/controllers/helpers.rb +269 -0
  36. data/lib/devise/controllers/rememberable.rb +52 -0
  37. data/lib/devise/controllers/scoped_views.rb +17 -0
  38. data/lib/devise/controllers/url_helpers.rb +67 -0
  39. data/lib/devise/delegator.rb +17 -0
  40. data/lib/devise/encryptors/authlogic_sha512.rb +19 -0
  41. data/lib/devise/encryptors/base.rb +24 -0
  42. data/lib/devise/encryptors/clearance_sha1.rb +17 -0
  43. data/lib/devise/encryptors/restful_authentication_sha1.rb +22 -0
  44. data/lib/devise/encryptors/sha1.rb +25 -0
  45. data/lib/devise/encryptors/sha512.rb +25 -0
  46. data/lib/devise/failure_app.rb +185 -0
  47. data/lib/devise/hooks/activatable.rb +11 -0
  48. data/lib/devise/hooks/forgetable.rb +9 -0
  49. data/lib/devise/hooks/lockable.rb +7 -0
  50. data/lib/devise/hooks/rememberable.rb +6 -0
  51. data/lib/devise/hooks/timeoutable.rb +22 -0
  52. data/lib/devise/hooks/trackable.rb +9 -0
  53. data/lib/devise/mailers/helpers.rb +86 -0
  54. data/lib/devise/mapping.rb +172 -0
  55. data/lib/devise/models.rb +123 -0
  56. data/lib/devise/models/authenticatable.rb +231 -0
  57. data/lib/devise/models/confirmable.rb +242 -0
  58. data/lib/devise/models/database_authenticatable.rb +126 -0
  59. data/lib/devise/models/encryptable.rb +86 -0
  60. data/lib/devise/models/lockable.rb +185 -0
  61. data/lib/devise/models/omniauthable.rb +27 -0
  62. data/lib/devise/models/recoverable.rb +140 -0
  63. data/lib/devise/models/registerable.rb +25 -0
  64. data/lib/devise/models/rememberable.rb +125 -0
  65. data/lib/devise/models/timeoutable.rb +49 -0
  66. data/lib/devise/models/token_authenticatable.rb +77 -0
  67. data/lib/devise/models/trackable.rb +35 -0
  68. data/lib/devise/models/validatable.rb +66 -0
  69. data/lib/devise/modules.rb +30 -0
  70. data/lib/devise/omniauth.rb +28 -0
  71. data/lib/devise/omniauth/config.rb +45 -0
  72. data/lib/devise/omniauth/url_helpers.rb +33 -0
  73. data/lib/devise/orm/active_record.rb +3 -0
  74. data/lib/devise/orm/mongoid.rb +3 -0
  75. data/lib/devise/param_filter.rb +41 -0
  76. data/lib/devise/rails.rb +54 -0
  77. data/lib/devise/rails/routes.rb +412 -0
  78. data/lib/devise/rails/warden_compat.rb +43 -0
  79. data/lib/devise/strategies/authenticatable.rb +165 -0
  80. data/lib/devise/strategies/base.rb +15 -0
  81. data/lib/devise/strategies/database_authenticatable.rb +21 -0
  82. data/lib/devise/strategies/rememberable.rb +53 -0
  83. data/lib/devise/strategies/token_authenticatable.rb +57 -0
  84. data/lib/devise/test_helpers.rb +130 -0
  85. data/lib/devise/version.rb +3 -0
  86. data/lib/generators/active_record/devise_generator.rb +78 -0
  87. data/lib/generators/active_record/templates/migration.rb +19 -0
  88. data/lib/generators/active_record/templates/migration_existing.rb +26 -0
  89. data/lib/generators/devise/devise_generator.rb +24 -0
  90. data/lib/generators/devise/install_generator.rb +24 -0
  91. data/lib/generators/devise/orm_helpers.rb +32 -0
  92. data/lib/generators/devise/views_generator.rb +110 -0
  93. data/lib/generators/mongoid/devise_generator.rb +60 -0
  94. data/lib/generators/templates/README +31 -0
  95. data/lib/generators/templates/devise.rb +216 -0
  96. data/lib/generators/templates/markerb/confirmation_instructions.markerb +5 -0
  97. data/lib/generators/templates/markerb/reset_password_instructions.markerb +8 -0
  98. data/lib/generators/templates/markerb/unlock_instructions.markerb +7 -0
  99. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +15 -0
  100. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +19 -0
  101. data/lib/generators/templates/simple_form_for/passwords/new.html.erb +15 -0
  102. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +22 -0
  103. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +17 -0
  104. data/lib/generators/templates/simple_form_for/sessions/new.html.erb +15 -0
  105. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +15 -0
  106. data/test/controllers/custom_strategy_test.rb +62 -0
  107. data/test/controllers/helpers_test.rb +254 -0
  108. data/test/controllers/internal_helpers_test.rb +97 -0
  109. data/test/controllers/sessions_controller_test.rb +36 -0
  110. data/test/controllers/url_helpers_test.rb +59 -0
  111. data/test/delegator_test.rb +19 -0
  112. data/test/devise_test.rb +72 -0
  113. data/test/encryptors_test.rb +30 -0
  114. data/test/failure_app_test.rb +211 -0
  115. data/test/generators/active_record_generator_test.rb +69 -0
  116. data/test/generators/devise_generator_test.rb +39 -0
  117. data/test/generators/install_generator_test.rb +13 -0
  118. data/test/generators/mongoid_generator_test.rb +23 -0
  119. data/test/generators/views_generator_test.rb +52 -0
  120. data/test/helpers/devise_helper_test.rb +51 -0
  121. data/test/indifferent_hash.rb +33 -0
  122. data/test/integration/authenticatable_test.rb +587 -0
  123. data/test/integration/confirmable_test.rb +255 -0
  124. data/test/integration/database_authenticatable_test.rb +82 -0
  125. data/test/integration/http_authenticatable_test.rb +97 -0
  126. data/test/integration/lockable_test.rb +224 -0
  127. data/test/integration/omniauthable_test.rb +133 -0
  128. data/test/integration/recoverable_test.rb +300 -0
  129. data/test/integration/registerable_test.rb +324 -0
  130. data/test/integration/rememberable_test.rb +158 -0
  131. data/test/integration/timeoutable_test.rb +114 -0
  132. data/test/integration/token_authenticatable_test.rb +161 -0
  133. data/test/integration/trackable_test.rb +92 -0
  134. data/test/mailers/confirmation_instructions_test.rb +95 -0
  135. data/test/mailers/reset_password_instructions_test.rb +83 -0
  136. data/test/mailers/unlock_instructions_test.rb +77 -0
  137. data/test/mapping_test.rb +127 -0
  138. data/test/models/authenticatable_test.rb +7 -0
  139. data/test/models/confirmable_test.rb +357 -0
  140. data/test/models/database_authenticatable_test.rb +189 -0
  141. data/test/models/encryptable_test.rb +73 -0
  142. data/test/models/lockable_test.rb +263 -0
  143. data/test/models/omniauthable_test.rb +7 -0
  144. data/test/models/recoverable_test.rb +205 -0
  145. data/test/models/registerable_test.rb +7 -0
  146. data/test/models/rememberable_test.rb +174 -0
  147. data/test/models/serializable_test.rb +48 -0
  148. data/test/models/timeoutable_test.rb +46 -0
  149. data/test/models/token_authenticatable_test.rb +55 -0
  150. data/test/models/trackable_test.rb +13 -0
  151. data/test/models/validatable_test.rb +117 -0
  152. data/test/models_test.rb +179 -0
  153. data/test/omniauth/config_test.rb +57 -0
  154. data/test/omniauth/url_helpers_test.rb +58 -0
  155. data/test/orm/active_record.rb +9 -0
  156. data/test/orm/mongoid.rb +14 -0
  157. data/test/rails_app/Rakefile +10 -0
  158. data/test/rails_app/app/active_record/admin.rb +6 -0
  159. data/test/rails_app/app/active_record/shim.rb +2 -0
  160. data/test/rails_app/app/active_record/user.rb +6 -0
  161. data/test/rails_app/app/controllers/admins/sessions_controller.rb +6 -0
  162. data/test/rails_app/app/controllers/admins_controller.rb +6 -0
  163. data/test/rails_app/app/controllers/application_controller.rb +8 -0
  164. data/test/rails_app/app/controllers/home_controller.rb +25 -0
  165. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +2 -0
  166. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +2 -0
  167. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +14 -0
  168. data/test/rails_app/app/controllers/users_controller.rb +23 -0
  169. data/test/rails_app/app/helpers/application_helper.rb +3 -0
  170. data/test/rails_app/app/mailers/users/mailer.rb +3 -0
  171. data/test/rails_app/app/mongoid/admin.rb +30 -0
  172. data/test/rails_app/app/mongoid/shim.rb +24 -0
  173. data/test/rails_app/app/mongoid/user.rb +45 -0
  174. data/test/rails_app/app/views/admins/index.html.erb +1 -0
  175. data/test/rails_app/app/views/admins/sessions/new.html.erb +2 -0
  176. data/test/rails_app/app/views/home/admin_dashboard.html.erb +1 -0
  177. data/test/rails_app/app/views/home/index.html.erb +1 -0
  178. data/test/rails_app/app/views/home/join.html.erb +1 -0
  179. data/test/rails_app/app/views/home/private.html.erb +1 -0
  180. data/test/rails_app/app/views/home/user_dashboard.html.erb +1 -0
  181. data/test/rails_app/app/views/layouts/application.html.erb +24 -0
  182. data/test/rails_app/app/views/users/index.html.erb +1 -0
  183. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +1 -0
  184. data/test/rails_app/app/views/users/sessions/new.html.erb +1 -0
  185. data/test/rails_app/config.ru +4 -0
  186. data/test/rails_app/config/application.rb +41 -0
  187. data/test/rails_app/config/boot.rb +8 -0
  188. data/test/rails_app/config/database.yml +18 -0
  189. data/test/rails_app/config/environment.rb +5 -0
  190. data/test/rails_app/config/environments/development.rb +18 -0
  191. data/test/rails_app/config/environments/production.rb +33 -0
  192. data/test/rails_app/config/environments/test.rb +33 -0
  193. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  194. data/test/rails_app/config/initializers/devise.rb +186 -0
  195. data/test/rails_app/config/initializers/inflections.rb +2 -0
  196. data/test/rails_app/config/initializers/secret_token.rb +2 -0
  197. data/test/rails_app/config/routes.rb +90 -0
  198. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +77 -0
  199. data/test/rails_app/db/schema.rb +52 -0
  200. data/test/rails_app/lib/shared_admin.rb +14 -0
  201. data/test/rails_app/lib/shared_user.rb +26 -0
  202. data/test/rails_app/public/404.html +26 -0
  203. data/test/rails_app/public/422.html +26 -0
  204. data/test/rails_app/public/500.html +26 -0
  205. data/test/rails_app/public/favicon.ico +0 -0
  206. data/test/rails_app/script/rails +10 -0
  207. data/test/routes_test.rb +248 -0
  208. data/test/support/assertions.rb +42 -0
  209. data/test/support/helpers.rb +91 -0
  210. data/test/support/integration.rb +90 -0
  211. data/test/support/locale/en.yml +4 -0
  212. data/test/support/webrat/integrations/rails.rb +24 -0
  213. data/test/test_helper.rb +27 -0
  214. data/test/test_helpers_test.rb +134 -0
  215. metadata +451 -0
@@ -0,0 +1,17 @@
1
+ require "digest/sha1"
2
+
3
+ module Devise
4
+ module Encryptors
5
+ # = ClearanceSha1
6
+ # Simulates Clearance's default encryption mechanism.
7
+ # Warning: it uses Devise's pepper to port the concept of REST_AUTH_SITE_KEY
8
+ # Warning: it uses Devise's stretches configuration to port the concept of REST_AUTH_DIGEST_STRETCHES
9
+ class ClearanceSha1 < Base
10
+ # Generates a default password digest based on salt, pepper and the
11
+ # incoming password.
12
+ def self.digest(password, stretches, salt, pepper)
13
+ Digest::SHA1.hexdigest("--#{salt}--#{password}--")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ require "digest/sha1"
2
+
3
+ module Devise
4
+ module Encryptors
5
+ # = RestfulAuthenticationSha1
6
+ # Simulates Restful Authentication's default encryption mechanism.
7
+ # Warning: it uses Devise's pepper to port the concept of REST_AUTH_SITE_KEY
8
+ # Warning: it uses Devise's stretches configuration to port the concept of REST_AUTH_DIGEST_STRETCHES. Should be set to 10 in
9
+ # the initializer to simulate the default behavior.
10
+ class RestfulAuthenticationSha1 < Base
11
+
12
+ # Generates a default password digest based on salt, pepper and the
13
+ # incoming password.
14
+ def self.digest(password, stretches, salt, pepper)
15
+ digest = pepper
16
+ stretches.times { digest = Digest::SHA1.hexdigest([digest, salt, password, pepper].flatten.join('--')) }
17
+ digest
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ require "digest/sha1"
2
+
3
+ module Devise
4
+ module Encryptors
5
+ # = Sha1
6
+ # Uses the Sha1 hash algorithm to encrypt passwords.
7
+ class Sha1 < Base
8
+ # Generates a default password digest based on stretches, salt, pepper and the
9
+ # incoming password.
10
+ def self.digest(password, stretches, salt, pepper)
11
+ digest = pepper
12
+ stretches.times { digest = self.secure_digest(salt, digest, password, pepper) }
13
+ digest
14
+ end
15
+
16
+ private
17
+
18
+ # Generate a SHA1 digest joining args. Generated token is something like
19
+ # --arg1--arg2--arg3--argN--
20
+ def self.secure_digest(*tokens)
21
+ ::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ require "digest/sha2"
2
+
3
+ module Devise
4
+ module Encryptors
5
+ # = Sha512
6
+ # Uses the Sha512 hash algorithm to encrypt passwords.
7
+ class Sha512 < Base
8
+ # Generates a default password digest based on salt, pepper and the
9
+ # incoming password.
10
+ def self.digest(password, stretches, salt, pepper)
11
+ digest = pepper
12
+ stretches.times { digest = self.secure_digest(salt, digest, password, pepper) }
13
+ digest
14
+ end
15
+
16
+ private
17
+
18
+ # Generate a Sha512 digest joining args. Generated token is something like
19
+ # --arg1--arg2--arg3--argN--
20
+ def self.secure_digest(*tokens)
21
+ ::Digest::SHA512.hexdigest('--' << tokens.flatten.join('--') << '--')
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,185 @@
1
+ require "action_controller/metal"
2
+
3
+ module Devise
4
+ # Failure application that will be called every time :warden is thrown from
5
+ # any strategy or hook. Responsible for redirect the user to the sign in
6
+ # page based on current scope and mapping. If no scope is given, redirect
7
+ # to the default_url.
8
+ class FailureApp < ActionController::Metal
9
+ include ActionController::RackDelegation
10
+ include ActionController::UrlFor
11
+ include ActionController::Redirecting
12
+
13
+ include Rails.application.routes.url_helpers
14
+ include Rails.application.routes.mounted_helpers
15
+
16
+ delegate :flash, :to => :request
17
+
18
+ def self.call(env)
19
+ @respond ||= action(:respond)
20
+ @respond.call(env)
21
+ end
22
+
23
+ def self.default_url_options(*args)
24
+ if defined?(ApplicationController)
25
+ ApplicationController.default_url_options(*args)
26
+ else
27
+ {}
28
+ end
29
+ end
30
+
31
+ def respond
32
+ if http_auth?
33
+ http_auth
34
+ elsif warden_options[:recall]
35
+ recall
36
+ else
37
+ redirect
38
+ end
39
+ end
40
+
41
+ def http_auth
42
+ self.status = 401
43
+ self.headers["WWW-Authenticate"] = %(Basic realm=#{Devise.http_authentication_realm.inspect}) if http_auth_header?
44
+ self.content_type = request.format.to_s
45
+ self.response_body = http_auth_body
46
+ end
47
+
48
+ def recall
49
+ env["PATH_INFO"] = attempted_path
50
+ flash.now[:alert] = i18n_message(:invalid)
51
+ self.response = recall_app(warden_options[:recall]).call(env)
52
+ end
53
+
54
+ def redirect
55
+ store_location!
56
+ if flash[:timedout] && flash[:alert]
57
+ flash.keep(:timedout)
58
+ flash.keep(:alert)
59
+ else
60
+ flash[:alert] = i18n_message
61
+ end
62
+ redirect_to redirect_url
63
+ end
64
+
65
+ protected
66
+
67
+ def i18n_message(default = nil)
68
+ message = warden_message || default || :unauthenticated
69
+
70
+ if message.is_a?(Symbol)
71
+ I18n.t(:"#{scope}.#{message}", :resource_name => scope,
72
+ :scope => "devise.failure", :default => [message])
73
+ else
74
+ message.to_s
75
+ end
76
+ end
77
+
78
+ def redirect_url
79
+ if warden_message == :timeout
80
+ flash[:timedout] = true
81
+ attempted_path || scope_path
82
+ else
83
+ scope_path
84
+ end
85
+ end
86
+
87
+ def scope_path
88
+ opts = {}
89
+ route = :"new_#{scope}_session_path"
90
+ opts[:format] = request_format unless skip_format?
91
+ opts[:script_name] = nil
92
+
93
+ context = send(Devise.available_router_name)
94
+
95
+ if context.respond_to?(route)
96
+ context.send(route, opts)
97
+ elsif respond_to?(:root_path)
98
+ root_path(opts)
99
+ else
100
+ "/"
101
+ end
102
+ end
103
+
104
+ def skip_format?
105
+ %w(html */*).include? request_format.to_s
106
+ end
107
+
108
+ # Choose whether we should respond in a http authentication fashion,
109
+ # including 401 and optional headers.
110
+ #
111
+ # This method allows the user to explicitly disable http authentication
112
+ # on ajax requests in case they want to redirect on failures instead of
113
+ # handling the errors on their own. This is useful in case your ajax API
114
+ # is the same as your public API and uses a format like JSON (so you
115
+ # cannot mark JSON as a navigational format).
116
+ def http_auth?
117
+ if request.xhr?
118
+ Devise.http_authenticatable_on_xhr
119
+ else
120
+ !(request_format && is_navigational_format?)
121
+ end
122
+ end
123
+
124
+ # It does not make sense to send authenticate headers in ajax requests
125
+ # or if the user disabled them.
126
+ def http_auth_header?
127
+ Devise.mappings[scope].to.http_authenticatable && !request.xhr?
128
+ end
129
+
130
+ def http_auth_body
131
+ return i18n_message unless request_format
132
+ method = "to_#{request_format}"
133
+ if method == "to_xml"
134
+ { :error => i18n_message }.to_xml(:root => "errors")
135
+ elsif {}.respond_to?(method)
136
+ { :error => i18n_message }.send(method)
137
+ else
138
+ i18n_message
139
+ end
140
+ end
141
+
142
+ def recall_app(app)
143
+ controller, action = app.split("#")
144
+ controller_name = ActiveSupport::Inflector.camelize(controller)
145
+ controller_klass = ActiveSupport::Inflector.constantize("#{controller_name}Controller")
146
+ controller_klass.action(action)
147
+ end
148
+
149
+ def warden
150
+ env['warden']
151
+ end
152
+
153
+ def warden_options
154
+ env['warden.options']
155
+ end
156
+
157
+ def warden_message
158
+ @message ||= warden.message || warden_options[:message]
159
+ end
160
+
161
+ def scope
162
+ @scope ||= warden_options[:scope] || Devise.default_scope
163
+ end
164
+
165
+ def attempted_path
166
+ warden_options[:attempted_path]
167
+ end
168
+
169
+ # Stores requested uri to redirect the user after signing in. We cannot use
170
+ # scoped session provided by warden here, since the user is not authenticated
171
+ # yet, but we still need to store the uri based on scope, so different scopes
172
+ # would never use the same uri to redirect.
173
+ def store_location!
174
+ session["#{scope}_return_to"] = attempted_path if request.get? && !http_auth?
175
+ end
176
+
177
+ def is_navigational_format?
178
+ Devise.navigational_formats.include?(request_format)
179
+ end
180
+
181
+ def request_format
182
+ @request_format ||= request.format.try(:ref)
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,11 @@
1
+ # Deny user access whenever his account is not active yet. All strategies that inherits from
2
+ # Devise::Strategies::Authenticatable and uses the validate already check if the user is active_for_authentication?
3
+ # before actively signing him in. However, we need this as hook to validate the user activity
4
+ # in each request and in case the user is using other strategies beside Devise ones.
5
+ Warden::Manager.after_set_user do |record, warden, options|
6
+ if record && record.respond_to?(:active_for_authentication?) && !record.active_for_authentication?
7
+ scope = options[:scope]
8
+ warden.logout(scope)
9
+ throw :warden, :scope => scope, :message => record.inactive_message
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ # Before logout hook to forget the user in the given scope, if it responds
2
+ # to forget_me! Also clear remember token to ensure the user won't be
3
+ # remembered again. Notice that we forget the user unless the record is not persisted.
4
+ # This avoids forgetting deleted users.
5
+ Warden::Manager.before_logout do |record, warden, options|
6
+ if record.respond_to?(:forget_me!)
7
+ Devise::Controllers::Rememberable::Proxy.new(warden).forget_me(record)
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ # After each sign in, if resource responds to failed_attempts, sets it to 0
2
+ # This is only triggered when the user is explicitly set (with set_user)
3
+ Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
4
+ if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
5
+ record.update_attribute(:failed_attempts, 0)
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
2
+ scope = options[:scope]
3
+ if record.respond_to?(:remember_me) && record.remember_me && warden.authenticated?(scope)
4
+ Devise::Controllers::Rememberable::Proxy.new(warden).remember_me(record)
5
+ end
6
+ end
@@ -0,0 +1,22 @@
1
+ # Each time a record is set we check whether its session has already timed out
2
+ # or not, based on last request time. If so, the record is logged out and
3
+ # redirected to the sign in page. Also, each time the request comes and the
4
+ # record is set, we set the last request time inside its scoped session to
5
+ # verify timeout in the following request.
6
+ Warden::Manager.after_set_user do |record, warden, options|
7
+ scope = options[:scope]
8
+
9
+ if record && record.respond_to?(:timedout?) && warden.authenticated?(scope) && options[:store] != false
10
+ last_request_at = warden.session(scope)['last_request_at']
11
+
12
+ if record.timedout?(last_request_at)
13
+ warden.logout(scope)
14
+ record.reset_authentication_token! if record.respond_to?(:reset_authentication_token!) && record.expire_auth_token_on_timeout
15
+ throw :warden, :scope => scope, :message => :timeout
16
+ end
17
+
18
+ unless warden.request.env['devise.skip_trackable']
19
+ warden.session(scope)['last_request_at'] = Time.now.utc
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ # After each sign in, update sign in time, sign in count and sign in IP.
2
+ # This is only triggered when the user is explicitly set (with set_user)
3
+ # and on authentication. Retrieving the user from session (:fetch) does
4
+ # not trigger it.
5
+ Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
6
+ if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope]) && !warden.request.env['devise.skip_trackable']
7
+ record.update_tracked_fields!(warden.request)
8
+ end
9
+ end
@@ -0,0 +1,86 @@
1
+ module Devise
2
+ module Mailers
3
+ module Helpers
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include Devise::Controllers::ScopedViews
8
+ attr_reader :scope_name, :resource
9
+ end
10
+
11
+ protected
12
+
13
+ # Configure default email options
14
+ def devise_mail(record, action)
15
+ initialize_from_record(record)
16
+ mail headers_for(action)
17
+ end
18
+
19
+ def initialize_from_record(record)
20
+ @scope_name = Devise::Mapping.find_scope!(record)
21
+ @resource = instance_variable_set("@#{devise_mapping.name}", record)
22
+ end
23
+
24
+ def devise_mapping
25
+ @devise_mapping ||= Devise.mappings[scope_name]
26
+ end
27
+
28
+ def headers_for(action)
29
+ headers = {
30
+ :subject => translate(devise_mapping, action),
31
+ :from => mailer_sender(devise_mapping),
32
+ :to => resource.email,
33
+ :template_path => template_paths
34
+ }
35
+
36
+ if resource.respond_to?(:headers_for)
37
+ headers.merge!(resource.headers_for(action))
38
+ end
39
+
40
+ unless headers.key?(:reply_to)
41
+ headers[:reply_to] = headers[:from]
42
+ end
43
+
44
+ headers
45
+ end
46
+
47
+ def mailer_sender(mapping)
48
+ if default_params[:from].present?
49
+ default_params[:from]
50
+ elsif Devise.mailer_sender.is_a?(Proc)
51
+ Devise.mailer_sender.call(mapping.name)
52
+ else
53
+ Devise.mailer_sender
54
+ end
55
+ end
56
+
57
+ def template_paths
58
+ template_path = [self.class.mailer_name]
59
+ template_path.unshift "#{@devise_mapping.scoped_path}/mailer" if self.class.scoped_views?
60
+ template_path
61
+ end
62
+
63
+ # Setup a subject doing an I18n lookup. At first, it attemps to set a subject
64
+ # based on the current mapping:
65
+ #
66
+ # en:
67
+ # devise:
68
+ # mailer:
69
+ # confirmation_instructions:
70
+ # user_subject: '...'
71
+ #
72
+ # If one does not exist, it fallbacks to ActionMailer default:
73
+ #
74
+ # en:
75
+ # devise:
76
+ # mailer:
77
+ # confirmation_instructions:
78
+ # subject: '...'
79
+ #
80
+ def translate(mapping, key)
81
+ I18n.t(:"#{mapping.name}_subject", :scope => [:devise, :mailer, key],
82
+ :default => [:subject, key.to_s.humanize])
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,172 @@
1
+ module Devise
2
+ # Responsible for handling devise mappings and routes configuration. Each
3
+ # resource configured by devise_for in routes is actually creating a mapping
4
+ # object. You can refer to devise_for in routes for usage options.
5
+ #
6
+ # The required value in devise_for is actually not used internally, but it's
7
+ # inflected to find all other values.
8
+ #
9
+ # map.devise_for :users
10
+ # mapping = Devise.mappings[:user]
11
+ #
12
+ # mapping.name #=> :user
13
+ # # is the scope used in controllers and warden, given in the route as :singular.
14
+ #
15
+ # mapping.as #=> "users"
16
+ # # how the mapping should be search in the path, given in the route as :as.
17
+ #
18
+ # mapping.to #=> User
19
+ # # is the class to be loaded from routes, given in the route as :class_name.
20
+ #
21
+ # mapping.modules #=> [:authenticatable]
22
+ # # is the modules included in the class
23
+ #
24
+ class Mapping #:nodoc:
25
+ attr_reader :singular, :scoped_path, :path, :controllers, :path_names,
26
+ :class_name, :sign_out_via, :format, :used_routes, :used_helpers, :failure_app
27
+
28
+ alias :name :singular
29
+
30
+ # Receives an object and find a scope for it. If a scope cannot be found,
31
+ # raises an error. If a symbol is given, it's considered to be the scope.
32
+ def self.find_scope!(duck)
33
+ case duck
34
+ when String, Symbol
35
+ return duck
36
+ when Class
37
+ Devise.mappings.each_value { |m| return m.name if duck <= m.to }
38
+ else
39
+ Devise.mappings.each_value { |m| return m.name if duck.is_a?(m.to) }
40
+ end
41
+
42
+ raise "Could not find a valid mapping for #{duck.inspect}"
43
+ end
44
+
45
+ def self.find_by_path!(path, path_type=:fullpath)
46
+ Devise.mappings.each_value { |m| return m if path.include?(m.send(path_type)) }
47
+ raise "Could not find a valid mapping for path #{path.inspect}"
48
+ end
49
+
50
+ def initialize(name, options) #:nodoc:
51
+ @scoped_path = options[:as] ? "#{options[:as]}/#{name}" : name.to_s
52
+ @singular = (options[:singular] || @scoped_path.tr('/', '_').singularize).to_sym
53
+
54
+ @class_name = (options[:class_name] || name.to_s.classify).to_s
55
+ @klass = Devise.ref(@class_name)
56
+
57
+ @path = (options[:path] || name).to_s
58
+ @path_prefix = options[:path_prefix]
59
+
60
+ @sign_out_via = options[:sign_out_via] || Devise.sign_out_via
61
+ @format = options[:format]
62
+
63
+ default_failure_app(options)
64
+ default_controllers(options)
65
+ default_path_names(options)
66
+ default_used_route(options)
67
+ default_used_helpers(options)
68
+ end
69
+
70
+ # Return modules for the mapping.
71
+ def modules
72
+ @modules ||= to.respond_to?(:devise_modules) ? to.devise_modules : []
73
+ end
74
+
75
+ # Gives the class the mapping points to.
76
+ def to
77
+ @klass.get
78
+ end
79
+
80
+ def strategies
81
+ @strategies ||= STRATEGIES.values_at(*self.modules).compact.uniq.reverse
82
+ end
83
+
84
+ def no_input_strategies
85
+ self.strategies & Devise::NO_INPUT
86
+ end
87
+
88
+ def routes
89
+ @routes ||= ROUTES.values_at(*self.modules).compact.uniq
90
+ end
91
+
92
+ def authenticatable?
93
+ @authenticatable ||= self.modules.any? { |m| m.to_s =~ /authenticatable/ }
94
+ end
95
+
96
+ def fullpath
97
+ "/#{@path_prefix}/#{@path}".squeeze("/")
98
+ end
99
+
100
+ # Create magic predicates for verifying what module is activated by this map.
101
+ # Example:
102
+ #
103
+ # def confirmable?
104
+ # self.modules.include?(:confirmable)
105
+ # end
106
+ #
107
+ def self.add_module(m)
108
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
109
+ def #{m}?
110
+ self.modules.include?(:#{m})
111
+ end
112
+ METHOD
113
+ end
114
+
115
+ private
116
+
117
+ def default_failure_app(options)
118
+ @failure_app = options[:failure_app] || Devise::FailureApp
119
+ if @failure_app.is_a?(String)
120
+ ref = Devise.ref(@failure_app)
121
+ @failure_app = lambda { |env| ref.get.call(env) }
122
+ end
123
+ end
124
+
125
+ def default_controllers(options)
126
+ mod = options[:module] || "devise"
127
+ @controllers = Hash.new { |h,k| h[k] = "#{mod}/#{k}" }
128
+ @controllers.merge!(options[:controllers]) if options[:controllers]
129
+ @controllers.each { |k,v| @controllers[k] = v.to_s }
130
+ end
131
+
132
+ def default_path_names(options)
133
+ @path_names = Hash.new { |h,k| h[k] = k.to_s }
134
+ @path_names[:registration] = ""
135
+ @path_names.merge!(options[:path_names]) if options[:path_names]
136
+ end
137
+
138
+ def default_constraints(options)
139
+ @constraints = Hash.new
140
+ @constraints.merge!(options[:constraints]) if options[:constraints]
141
+ end
142
+
143
+ def default_defaults(options)
144
+ @defaults = Hash.new
145
+ @defaults.merge!(options[:defaults]) if options[:defaults]
146
+ end
147
+
148
+ def default_used_route(options)
149
+ singularizer = lambda { |s| s.to_s.singularize.to_sym }
150
+
151
+ if options.has_key?(:only)
152
+ @used_routes = self.routes & Array(options[:only]).map(&singularizer)
153
+ elsif options[:skip] == :all
154
+ @used_routes = []
155
+ else
156
+ @used_routes = self.routes - Array(options[:skip]).map(&singularizer)
157
+ end
158
+ end
159
+
160
+ def default_used_helpers(options)
161
+ singularizer = lambda { |s| s.to_s.singularize.to_sym }
162
+
163
+ if options[:skip_helpers] == true
164
+ @used_helpers = @used_routes
165
+ elsif skip = options[:skip_helpers]
166
+ @used_helpers = self.routes - Array(skip).map(&singularizer)
167
+ else
168
+ @used_helpers = self.routes
169
+ end
170
+ end
171
+ end
172
+ end