devise 3.2.2 → 4.6.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 (235) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +242 -978
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +371 -100
  5. data/app/controllers/devise/confirmations_controller.rb +11 -5
  6. data/app/controllers/devise/omniauth_callbacks_controller.rb +12 -6
  7. data/app/controllers/devise/passwords_controller.rb +21 -8
  8. data/app/controllers/devise/registrations_controller.rb +59 -26
  9. data/app/controllers/devise/sessions_controller.rb +47 -17
  10. data/app/controllers/devise/unlocks_controller.rb +9 -4
  11. data/app/controllers/devise_controller.rb +67 -31
  12. data/app/helpers/devise_helper.rb +12 -19
  13. data/app/mailers/devise/mailer.rb +10 -0
  14. data/app/views/devise/confirmations/new.html.erb +9 -5
  15. data/app/views/devise/mailer/confirmation_instructions.html.erb +1 -1
  16. data/app/views/devise/mailer/email_changed.html.erb +7 -0
  17. data/app/views/devise/mailer/password_change.html.erb +3 -0
  18. data/app/views/devise/mailer/reset_password_instructions.html.erb +1 -1
  19. data/app/views/devise/mailer/unlock_instructions.html.erb +1 -1
  20. data/app/views/devise/passwords/edit.html.erb +16 -7
  21. data/app/views/devise/passwords/new.html.erb +9 -5
  22. data/app/views/devise/registrations/edit.html.erb +29 -15
  23. data/app/views/devise/registrations/new.html.erb +20 -9
  24. data/app/views/devise/sessions/new.html.erb +19 -10
  25. data/app/views/devise/shared/_error_messages.html.erb +15 -0
  26. data/app/views/devise/shared/{_links.erb → _links.html.erb} +9 -9
  27. data/app/views/devise/unlocks/new.html.erb +9 -5
  28. data/config/locales/en.yml +23 -17
  29. data/lib/devise/controllers/helpers.rb +112 -32
  30. data/lib/devise/controllers/rememberable.rb +15 -6
  31. data/lib/devise/controllers/scoped_views.rb +3 -1
  32. data/lib/devise/controllers/sign_in_out.rb +42 -26
  33. data/lib/devise/controllers/store_location.rb +31 -5
  34. data/lib/devise/controllers/url_helpers.rb +9 -7
  35. data/lib/devise/delegator.rb +2 -0
  36. data/lib/devise/encryptor.rb +24 -0
  37. data/lib/devise/failure_app.rb +125 -39
  38. data/lib/devise/hooks/activatable.rb +7 -6
  39. data/lib/devise/hooks/csrf_cleaner.rb +5 -1
  40. data/lib/devise/hooks/forgetable.rb +2 -0
  41. data/lib/devise/hooks/lockable.rb +7 -2
  42. data/lib/devise/hooks/proxy.rb +4 -2
  43. data/lib/devise/hooks/rememberable.rb +4 -2
  44. data/lib/devise/hooks/timeoutable.rb +16 -9
  45. data/lib/devise/hooks/trackable.rb +3 -1
  46. data/lib/devise/mailers/helpers.rb +15 -12
  47. data/lib/devise/mapping.rb +8 -2
  48. data/lib/devise/models/authenticatable.rb +82 -56
  49. data/lib/devise/models/confirmable.rb +125 -42
  50. data/lib/devise/models/database_authenticatable.rb +110 -32
  51. data/lib/devise/models/lockable.rb +30 -17
  52. data/lib/devise/models/omniauthable.rb +3 -1
  53. data/lib/devise/models/recoverable.rb +62 -26
  54. data/lib/devise/models/registerable.rb +4 -0
  55. data/lib/devise/models/rememberable.rb +62 -33
  56. data/lib/devise/models/timeoutable.rb +4 -8
  57. data/lib/devise/models/trackable.rb +20 -4
  58. data/lib/devise/models/validatable.rb +16 -9
  59. data/lib/devise/models.rb +3 -1
  60. data/lib/devise/modules.rb +12 -10
  61. data/lib/devise/omniauth/config.rb +2 -0
  62. data/lib/devise/omniauth/url_helpers.rb +14 -5
  63. data/lib/devise/omniauth.rb +2 -0
  64. data/lib/devise/orm/active_record.rb +5 -1
  65. data/lib/devise/orm/mongoid.rb +6 -2
  66. data/lib/devise/parameter_filter.rb +4 -0
  67. data/lib/devise/parameter_sanitizer.rb +139 -65
  68. data/lib/devise/rails/routes.rb +147 -116
  69. data/lib/devise/rails/warden_compat.rb +3 -10
  70. data/lib/devise/rails.rb +10 -13
  71. data/lib/devise/secret_key_finder.rb +27 -0
  72. data/lib/devise/strategies/authenticatable.rb +20 -9
  73. data/lib/devise/strategies/base.rb +3 -1
  74. data/lib/devise/strategies/database_authenticatable.rb +14 -6
  75. data/lib/devise/strategies/rememberable.rb +15 -3
  76. data/lib/devise/test/controller_helpers.rb +165 -0
  77. data/lib/devise/test/integration_helpers.rb +63 -0
  78. data/lib/devise/test_helpers.rb +7 -124
  79. data/lib/devise/time_inflector.rb +4 -2
  80. data/lib/devise/token_generator.rb +3 -41
  81. data/lib/devise/version.rb +3 -1
  82. data/lib/devise.rb +111 -84
  83. data/lib/generators/active_record/devise_generator.rb +49 -12
  84. data/lib/generators/active_record/templates/migration.rb +9 -7
  85. data/lib/generators/active_record/templates/migration_existing.rb +9 -7
  86. data/lib/generators/devise/controllers_generator.rb +46 -0
  87. data/lib/generators/devise/devise_generator.rb +7 -5
  88. data/lib/generators/devise/install_generator.rb +21 -0
  89. data/lib/generators/devise/orm_helpers.rb +10 -21
  90. data/lib/generators/devise/views_generator.rb +49 -28
  91. data/lib/generators/mongoid/devise_generator.rb +21 -19
  92. data/lib/generators/templates/README +5 -12
  93. data/lib/generators/templates/controllers/README +14 -0
  94. data/lib/generators/templates/controllers/confirmations_controller.rb +30 -0
  95. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +30 -0
  96. data/lib/generators/templates/controllers/passwords_controller.rb +34 -0
  97. data/lib/generators/templates/controllers/registrations_controller.rb +62 -0
  98. data/lib/generators/templates/controllers/sessions_controller.rb +27 -0
  99. data/lib/generators/templates/controllers/unlocks_controller.rb +30 -0
  100. data/lib/generators/templates/devise.rb +81 -36
  101. data/lib/generators/templates/markerb/confirmation_instructions.markerb +1 -1
  102. data/lib/generators/templates/markerb/email_changed.markerb +7 -0
  103. data/lib/generators/templates/markerb/password_change.markerb +3 -0
  104. data/lib/generators/templates/markerb/reset_password_instructions.markerb +1 -1
  105. data/lib/generators/templates/markerb/unlock_instructions.markerb +1 -1
  106. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +6 -2
  107. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +9 -4
  108. data/lib/generators/templates/simple_form_for/passwords/new.html.erb +5 -2
  109. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +14 -6
  110. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +12 -4
  111. data/lib/generators/templates/simple_form_for/sessions/new.html.erb +11 -6
  112. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +5 -2
  113. metadata +52 -280
  114. data/.gitignore +0 -10
  115. data/.travis.yml +0 -20
  116. data/.yardopts +0 -9
  117. data/CONTRIBUTING.md +0 -14
  118. data/Gemfile +0 -31
  119. data/Gemfile.lock +0 -160
  120. data/Rakefile +0 -35
  121. data/devise.gemspec +0 -27
  122. data/devise.png +0 -0
  123. data/gemfiles/Gemfile.rails-3.2.x +0 -31
  124. data/gemfiles/Gemfile.rails-3.2.x.lock +0 -159
  125. data/test/controllers/custom_strategy_test.rb +0 -62
  126. data/test/controllers/helpers_test.rb +0 -276
  127. data/test/controllers/internal_helpers_test.rb +0 -120
  128. data/test/controllers/passwords_controller_test.rb +0 -31
  129. data/test/controllers/sessions_controller_test.rb +0 -99
  130. data/test/controllers/url_helpers_test.rb +0 -59
  131. data/test/delegator_test.rb +0 -19
  132. data/test/devise_test.rb +0 -94
  133. data/test/failure_app_test.rb +0 -232
  134. data/test/generators/active_record_generator_test.rb +0 -103
  135. data/test/generators/devise_generator_test.rb +0 -39
  136. data/test/generators/install_generator_test.rb +0 -13
  137. data/test/generators/mongoid_generator_test.rb +0 -23
  138. data/test/generators/views_generator_test.rb +0 -67
  139. data/test/helpers/devise_helper_test.rb +0 -51
  140. data/test/integration/authenticatable_test.rb +0 -713
  141. data/test/integration/confirmable_test.rb +0 -284
  142. data/test/integration/database_authenticatable_test.rb +0 -84
  143. data/test/integration/http_authenticatable_test.rb +0 -105
  144. data/test/integration/lockable_test.rb +0 -239
  145. data/test/integration/omniauthable_test.rb +0 -133
  146. data/test/integration/recoverable_test.rb +0 -334
  147. data/test/integration/registerable_test.rb +0 -349
  148. data/test/integration/rememberable_test.rb +0 -167
  149. data/test/integration/timeoutable_test.rb +0 -183
  150. data/test/integration/trackable_test.rb +0 -92
  151. data/test/mailers/confirmation_instructions_test.rb +0 -115
  152. data/test/mailers/reset_password_instructions_test.rb +0 -96
  153. data/test/mailers/unlock_instructions_test.rb +0 -91
  154. data/test/mapping_test.rb +0 -127
  155. data/test/models/authenticatable_test.rb +0 -13
  156. data/test/models/confirmable_test.rb +0 -454
  157. data/test/models/database_authenticatable_test.rb +0 -249
  158. data/test/models/lockable_test.rb +0 -298
  159. data/test/models/omniauthable_test.rb +0 -7
  160. data/test/models/recoverable_test.rb +0 -184
  161. data/test/models/registerable_test.rb +0 -7
  162. data/test/models/rememberable_test.rb +0 -183
  163. data/test/models/serializable_test.rb +0 -49
  164. data/test/models/timeoutable_test.rb +0 -51
  165. data/test/models/trackable_test.rb +0 -13
  166. data/test/models/validatable_test.rb +0 -127
  167. data/test/models_test.rb +0 -144
  168. data/test/omniauth/config_test.rb +0 -57
  169. data/test/omniauth/url_helpers_test.rb +0 -54
  170. data/test/orm/active_record.rb +0 -10
  171. data/test/orm/mongoid.rb +0 -13
  172. data/test/parameter_sanitizer_test.rb +0 -81
  173. data/test/rails_app/Rakefile +0 -6
  174. data/test/rails_app/app/active_record/admin.rb +0 -6
  175. data/test/rails_app/app/active_record/shim.rb +0 -2
  176. data/test/rails_app/app/active_record/user.rb +0 -6
  177. data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -6
  178. data/test/rails_app/app/controllers/admins_controller.rb +0 -11
  179. data/test/rails_app/app/controllers/application_controller.rb +0 -9
  180. data/test/rails_app/app/controllers/home_controller.rb +0 -25
  181. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -2
  182. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -2
  183. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -14
  184. data/test/rails_app/app/controllers/users_controller.rb +0 -31
  185. data/test/rails_app/app/helpers/application_helper.rb +0 -3
  186. data/test/rails_app/app/mailers/users/mailer.rb +0 -12
  187. data/test/rails_app/app/mongoid/admin.rb +0 -29
  188. data/test/rails_app/app/mongoid/shim.rb +0 -23
  189. data/test/rails_app/app/mongoid/user.rb +0 -39
  190. data/test/rails_app/app/views/admins/index.html.erb +0 -1
  191. data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
  192. data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
  193. data/test/rails_app/app/views/home/index.html.erb +0 -1
  194. data/test/rails_app/app/views/home/join.html.erb +0 -1
  195. data/test/rails_app/app/views/home/private.html.erb +0 -1
  196. data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
  197. data/test/rails_app/app/views/layouts/application.html.erb +0 -24
  198. data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
  199. data/test/rails_app/app/views/users/index.html.erb +0 -1
  200. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
  201. data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
  202. data/test/rails_app/bin/bundle +0 -3
  203. data/test/rails_app/bin/rails +0 -4
  204. data/test/rails_app/bin/rake +0 -4
  205. data/test/rails_app/config/application.rb +0 -40
  206. data/test/rails_app/config/boot.rb +0 -14
  207. data/test/rails_app/config/database.yml +0 -18
  208. data/test/rails_app/config/environment.rb +0 -5
  209. data/test/rails_app/config/environments/development.rb +0 -30
  210. data/test/rails_app/config/environments/production.rb +0 -80
  211. data/test/rails_app/config/environments/test.rb +0 -36
  212. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -7
  213. data/test/rails_app/config/initializers/devise.rb +0 -181
  214. data/test/rails_app/config/initializers/inflections.rb +0 -2
  215. data/test/rails_app/config/initializers/secret_token.rb +0 -8
  216. data/test/rails_app/config/initializers/session_store.rb +0 -1
  217. data/test/rails_app/config/routes.rb +0 -104
  218. data/test/rails_app/config.ru +0 -4
  219. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -71
  220. data/test/rails_app/db/schema.rb +0 -55
  221. data/test/rails_app/lib/shared_admin.rb +0 -17
  222. data/test/rails_app/lib/shared_user.rb +0 -29
  223. data/test/rails_app/public/404.html +0 -26
  224. data/test/rails_app/public/422.html +0 -26
  225. data/test/rails_app/public/500.html +0 -26
  226. data/test/rails_app/public/favicon.ico +0 -0
  227. data/test/routes_test.rb +0 -250
  228. data/test/support/assertions.rb +0 -40
  229. data/test/support/helpers.rb +0 -70
  230. data/test/support/integration.rb +0 -92
  231. data/test/support/locale/en.yml +0 -8
  232. data/test/support/webrat/integrations/rails.rb +0 -24
  233. data/test/test_helper.rb +0 -27
  234. data/test/test_helpers_test.rb +0 -173
  235. data/test/test_models.rb +0 -33
@@ -1,12 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "action_controller/metal"
2
4
 
3
5
  module Devise
4
6
  # 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.
7
+ # any strategy or hook. It is responsible for redirecting the user to the sign
8
+ # in page based on current scope and mapping. If no scope is given, it
9
+ # redirects to the default_url.
8
10
  class FailureApp < ActionController::Metal
9
- include ActionController::RackDelegation
10
11
  include ActionController::UrlFor
11
12
  include ActionController::Redirecting
12
13
 
@@ -15,16 +16,19 @@ module Devise
15
16
 
16
17
  include Devise::Controllers::StoreLocation
17
18
 
18
- delegate :flash, :to => :request
19
+ delegate :flash, to: :request
19
20
 
20
21
  def self.call(env)
21
22
  @respond ||= action(:respond)
22
23
  @respond.call(env)
23
24
  end
24
25
 
26
+ # Try retrieving the URL options from the parent controller (usually
27
+ # ApplicationController). Instance methods are not supported at the moment,
28
+ # so only the class-level attribute is used.
25
29
  def self.default_url_options(*args)
26
- if defined?(ApplicationController)
27
- ApplicationController.default_url_options(*args)
30
+ if defined?(Devise.parent_controller.constantize)
31
+ Devise.parent_controller.constantize.try(:default_url_options) || {}
28
32
  else
29
33
  {}
30
34
  end
@@ -48,18 +52,38 @@ module Devise
48
52
  end
49
53
 
50
54
  def recall
51
- env["PATH_INFO"] = attempted_path
52
- flash.now[:alert] = i18n_message(:invalid)
53
- self.response = recall_app(warden_options[:recall]).call(env)
55
+ header_info = if relative_url_root?
56
+ base_path = Pathname.new(relative_url_root)
57
+ full_path = Pathname.new(attempted_path)
58
+
59
+ { "SCRIPT_NAME" => relative_url_root,
60
+ "PATH_INFO" => '/' + full_path.relative_path_from(base_path).to_s }
61
+ else
62
+ { "PATH_INFO" => attempted_path }
63
+ end
64
+
65
+ header_info.each do | var, value|
66
+ if request.respond_to?(:set_header)
67
+ request.set_header(var, value)
68
+ else
69
+ request.env[var] = value
70
+ end
71
+ end
72
+
73
+ flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
74
+ # self.response = recall_app(warden_options[:recall]).call(env)
75
+ self.response = recall_app(warden_options[:recall]).call(request.env)
54
76
  end
55
77
 
56
78
  def redirect
57
79
  store_location!
58
- if flash[:timedout] && flash[:alert]
59
- flash.keep(:timedout)
60
- flash.keep(:alert)
61
- else
62
- flash[:alert] = i18n_message
80
+ if is_flashing_format?
81
+ if flash[:timedout] && flash[:alert]
82
+ flash.keep(:timedout)
83
+ flash.keep(:alert)
84
+ else
85
+ flash[:alert] = i18n_message
86
+ end
63
87
  end
64
88
  redirect_to redirect_url
65
89
  end
@@ -78,6 +102,9 @@ module Devise
78
102
  options[:resource_name] = scope
79
103
  options[:scope] = "devise.failure"
80
104
  options[:default] = [message]
105
+ auth_keys = scope_class.authentication_keys
106
+ keys = (auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys).map { |key| scope_class.human_attribute_name(key) }
107
+ options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
81
108
  options = i18n_options(options)
82
109
 
83
110
  I18n.t(:"#{scope}.#{message}", options)
@@ -88,7 +115,7 @@ module Devise
88
115
 
89
116
  def redirect_url
90
117
  if warden_message == :timeout
91
- flash[:timedout] = true
118
+ flash[:timedout] = true if is_flashing_format?
92
119
 
93
120
  path = if request.get?
94
121
  attempted_path
@@ -96,26 +123,45 @@ module Devise
96
123
  request.referrer
97
124
  end
98
125
 
99
- path || scope_path
126
+ path || scope_url
100
127
  else
101
- scope_path
128
+ scope_url
102
129
  end
103
130
  end
104
131
 
105
- def scope_path
132
+ def route(scope)
133
+ :"new_#{scope}_session_url"
134
+ end
135
+
136
+ def scope_url
106
137
  opts = {}
107
- route = :"new_#{scope}_session_path"
138
+
139
+ # Initialize script_name with nil to prevent infinite loops in
140
+ # authenticated mounted engines in rails 4.2 and 5.0
141
+ opts[:script_name] = nil
142
+
143
+ route = route(scope)
144
+
108
145
  opts[:format] = request_format unless skip_format?
109
146
 
110
- config = Rails.application.config
111
- opts[:script_name] = (config.relative_url_root if config.respond_to?(:relative_url_root))
147
+ router_name = Devise.mappings[scope].router_name || Devise.available_router_name
148
+ context = send(router_name)
112
149
 
113
- context = send(Devise.available_router_name)
150
+ if relative_url_root?
151
+ opts[:script_name] = relative_url_root
152
+
153
+ # We need to add the rootpath to `script_name` manually for applications that use a Rails
154
+ # version lower than 5.1. Otherwise, it is going to generate a wrong path for Engines
155
+ # that use Devise. Remove it when the support of Rails 5.0 is droped.
156
+ elsif root_path_defined?(context) && rails_5_and_down?
157
+ rootpath = context.routes.url_helpers.root_path
158
+ opts[:script_name] = rootpath.chomp('/') if rootpath.length > 1
159
+ end
114
160
 
115
161
  if context.respond_to?(route)
116
162
  context.send(route, opts)
117
- elsif respond_to?(:root_path)
118
- root_path(opts)
163
+ elsif respond_to?(:root_url)
164
+ root_url(opts)
119
165
  else
120
166
  "/"
121
167
  end
@@ -125,12 +171,12 @@ module Devise
125
171
  %w(html */*).include? request_format.to_s
126
172
  end
127
173
 
128
- # Choose whether we should respond in a http authentication fashion,
174
+ # Choose whether we should respond in an HTTP authentication fashion,
129
175
  # including 401 and optional headers.
130
176
  #
131
- # This method allows the user to explicitly disable http authentication
132
- # on ajax requests in case they want to redirect on failures instead of
133
- # handling the errors on their own. This is useful in case your ajax API
177
+ # This method allows the user to explicitly disable HTTP authentication
178
+ # on AJAX requests in case they want to redirect on failures instead of
179
+ # handling the errors on their own. This is useful in case your AJAX API
134
180
  # is the same as your public API and uses a format like JSON (so you
135
181
  # cannot mark JSON as a navigational format).
136
182
  def http_auth?
@@ -141,19 +187,19 @@ module Devise
141
187
  end
142
188
  end
143
189
 
144
- # It does not make sense to send authenticate headers in ajax requests
190
+ # It doesn't make sense to send authenticate headers in AJAX requests
145
191
  # or if the user disabled them.
146
192
  def http_auth_header?
147
- Devise.mappings[scope].to.http_authenticatable && !request.xhr?
193
+ scope_class.http_authenticatable && !request.xhr?
148
194
  end
149
195
 
150
196
  def http_auth_body
151
197
  return i18n_message unless request_format
152
198
  method = "to_#{request_format}"
153
199
  if method == "to_xml"
154
- { :error => i18n_message }.to_xml(:root => "errors")
200
+ { error: i18n_message }.to_xml(root: "errors")
155
201
  elsif {}.respond_to?(method)
156
- { :error => i18n_message }.send(method)
202
+ { error: i18n_message }.send(method)
157
203
  else
158
204
  i18n_message
159
205
  end
@@ -167,11 +213,11 @@ module Devise
167
213
  end
168
214
 
169
215
  def warden
170
- env['warden']
216
+ request.respond_to?(:get_header) ? request.get_header("warden") : request.env["warden"]
171
217
  end
172
218
 
173
219
  def warden_options
174
- env['warden.options']
220
+ request.respond_to?(:get_header) ? request.get_header("warden.options") : request.env["warden.options"]
175
221
  end
176
222
 
177
223
  def warden_message
@@ -182,14 +228,18 @@ module Devise
182
228
  @scope ||= warden_options[:scope] || Devise.default_scope
183
229
  end
184
230
 
231
+ def scope_class
232
+ @scope_class ||= Devise.mappings[scope].to
233
+ end
234
+
185
235
  def attempted_path
186
236
  warden_options[:attempted_path]
187
237
  end
188
238
 
189
- # Stores requested uri to redirect the user after signing in. We cannot use
190
- # scoped session provided by warden here, since the user is not authenticated
191
- # yet, but we still need to store the uri based on scope, so different scopes
192
- # would never use the same uri to redirect.
239
+ # Stores requested URI to redirect the user after signing in. We can't use
240
+ # the scoped session provided by warden here, since the user is not
241
+ # authenticated yet, but we still need to store the URI based on scope, so
242
+ # different scopes would never use the same URI to redirect.
193
243
  def store_location!
194
244
  store_location_for(scope, attempted_path) if request.get? && !http_auth?
195
245
  end
@@ -198,8 +248,44 @@ module Devise
198
248
  Devise.navigational_formats.include?(request_format)
199
249
  end
200
250
 
251
+ # Check if flash messages should be emitted. Default is to do it on
252
+ # navigational formats
253
+ def is_flashing_format?
254
+ request.respond_to?(:flash) && is_navigational_format?
255
+ end
256
+
201
257
  def request_format
202
258
  @request_format ||= request.format.try(:ref)
203
259
  end
260
+
261
+ def relative_url_root
262
+ @relative_url_root ||= begin
263
+ config = Rails.application.config
264
+
265
+ config.try(:relative_url_root) || config.action_controller.try(:relative_url_root)
266
+ end
267
+ end
268
+
269
+ def relative_url_root?
270
+ relative_url_root.present?
271
+ end
272
+
273
+ ActiveSupport.run_load_hooks(:devise_failure_app, self)
274
+
275
+ private
276
+
277
+ def root_path_defined?(context)
278
+ defined?(context.routes) && context.routes.url_helpers.root_path.present?
279
+ end
280
+
281
+ def rails_5_and_down?
282
+ return false if rails_5_up?
283
+
284
+ Rails::VERSION::MAJOR >= 4
285
+ end
286
+
287
+ def rails_5_up?
288
+ Rails::VERSION::MAJOR >= 5 && Rails::VERSION::MINOR > 0
289
+ end
204
290
  end
205
291
  end
@@ -1,11 +1,12 @@
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.
1
+ # frozen_string_literal: true
2
+
3
+ # Deny user access whenever their account is not active yet.
4
+ # We need this as hook to validate the user activity on each request
5
+ # and in case the user is using other strategies beside Devise ones.
5
6
  Warden::Manager.after_set_user do |record, warden, options|
6
7
  if record && record.respond_to?(:active_for_authentication?) && !record.active_for_authentication?
7
8
  scope = options[:scope]
8
9
  warden.logout(scope)
9
- throw :warden, :scope => scope, :message => record.inactive_message
10
+ throw :warden, scope: scope, message: record.inactive_message
10
11
  end
11
- end
12
+ end
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Warden::Manager.after_authentication do |record, warden, options|
2
- if Devise.clean_up_csrf_token_on_authentication
4
+ clean_up_for_winning_strategy = !warden.winning_strategy.respond_to?(:clean_up_csrf?) ||
5
+ warden.winning_strategy.clean_up_csrf?
6
+ if Devise.clean_up_csrf_token_on_authentication && clean_up_for_winning_strategy
3
7
  warden.request.session.try(:delete, :_csrf_token)
4
8
  end
5
9
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Before logout hook to forget the user in the given scope, if it responds
2
4
  # to forget_me! Also clear remember token to ensure the user won't be
3
5
  # remembered again. Notice that we forget the user unless the record is not persisted.
@@ -1,7 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # After each sign in, if resource responds to failed_attempts, sets it to 0
2
4
  # 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|
5
+ Warden::Manager.after_set_user except: :fetch do |record, warden, options|
4
6
  if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
5
- record.update_attribute(:failed_attempts, 0) unless record.failed_attempts.to_i.zero?
7
+ unless record.failed_attempts.to_i.zero?
8
+ record.failed_attempts = 0
9
+ record.save(validate: false)
10
+ end
6
11
  end
7
12
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  module Hooks
3
5
  # A small warden proxy so we can remember, forget and
@@ -7,7 +9,7 @@ module Devise
7
9
  include Devise::Controllers::SignInOut
8
10
 
9
11
  attr_reader :warden
10
- delegate :cookies, :env, :to => :warden
12
+ delegate :cookies, :request, to: :warden
11
13
 
12
14
  def initialize(warden)
13
15
  @warden = warden
@@ -18,4 +20,4 @@ module Devise
18
20
  end
19
21
  end
20
22
  end
21
- end
23
+ end
@@ -1,7 +1,9 @@
1
- Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
1
+ # frozen_string_literal: true
2
+
3
+ Warden::Manager.after_set_user except: :fetch do |record, warden, options|
2
4
  scope = options[:scope]
3
5
  if record.respond_to?(:remember_me) && options[:store] != false &&
4
6
  record.remember_me && warden.authenticated?(scope)
5
7
  Devise::Hooks::Proxy.new(warden).remember_me(record)
6
8
  end
7
- end
9
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Each time a record is set we check whether its session has already timed out
2
4
  # or not, based on last request time. If so, the record is logged out and
3
5
  # redirected to the sign in page. Also, each time the request comes and the
@@ -7,22 +9,27 @@ Warden::Manager.after_set_user do |record, warden, options|
7
9
  scope = options[:scope]
8
10
  env = warden.request.env
9
11
 
10
- if record && record.respond_to?(:timedout?) && warden.authenticated?(scope) && options[:store] != false
12
+ if record && record.respond_to?(:timedout?) && warden.authenticated?(scope) &&
13
+ options[:store] != false && !env['devise.skip_timeoutable']
11
14
  last_request_at = warden.session(scope)['last_request_at']
12
- proxy = Devise::Hooks::Proxy.new(warden)
13
15
 
14
- if record.timedout?(last_request_at) && !env['devise.skip_timeout']
15
- Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
16
+ if last_request_at.is_a? Integer
17
+ last_request_at = Time.at(last_request_at).utc
18
+ elsif last_request_at.is_a? String
19
+ last_request_at = Time.parse(last_request_at)
20
+ end
16
21
 
17
- if record.respond_to?(:expire_auth_token_on_timeout) && record.expire_auth_token_on_timeout
18
- record.reset_authentication_token!
19
- end
22
+ proxy = Devise::Hooks::Proxy.new(warden)
20
23
 
21
- throw :warden, :scope => scope, :message => :timeout
24
+ if record.timedout?(last_request_at) &&
25
+ !env['devise.skip_timeout'] &&
26
+ !proxy.remember_me_is_active?(record)
27
+ Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
28
+ throw :warden, scope: scope, message: :timeout
22
29
  end
23
30
 
24
31
  unless env['devise.skip_trackable']
25
- warden.session(scope)['last_request_at'] = Time.now.utc
32
+ warden.session(scope)['last_request_at'] = Time.now.utc.to_i
26
33
  end
27
34
  end
28
35
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # After each sign in, update sign in time, sign in count and sign in IP.
2
4
  # This is only triggered when the user is explicitly set (with set_user)
3
5
  # and on authentication. Retrieving the user from session (:fetch) does
4
6
  # not trigger it.
5
- Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
7
+ Warden::Manager.after_set_user except: :fetch do |record, warden, options|
6
8
  if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope]) && !warden.request.env['devise.skip_trackable']
7
9
  record.update_tracked_fields!(warden.request)
8
10
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  module Mailers
3
5
  module Helpers
@@ -5,15 +7,16 @@ module Devise
5
7
 
6
8
  included do
7
9
  include Devise::Controllers::ScopedViews
8
- attr_reader :scope_name, :resource
9
10
  end
10
11
 
11
12
  protected
12
13
 
14
+ attr_reader :scope_name, :resource
15
+
13
16
  # Configure default email options
14
- def devise_mail(record, action, opts={})
17
+ def devise_mail(record, action, opts = {}, &block)
15
18
  initialize_from_record(record)
16
- mail headers_for(action, opts)
19
+ mail headers_for(action, opts), &block
17
20
  end
18
21
 
19
22
  def initialize_from_record(record)
@@ -27,12 +30,12 @@ module Devise
27
30
 
28
31
  def headers_for(action, opts)
29
32
  headers = {
30
- :subject => subject_for(action),
31
- :to => resource.email,
32
- :from => mailer_sender(devise_mapping),
33
- :reply_to => mailer_reply_to(devise_mapping),
34
- :template_path => template_paths,
35
- :template_name => action
33
+ subject: subject_for(action),
34
+ to: resource.email,
35
+ from: mailer_sender(devise_mapping),
36
+ reply_to: mailer_reply_to(devise_mapping),
37
+ template_path: template_paths,
38
+ template_name: action
36
39
  }.merge(opts)
37
40
 
38
41
  @email = headers[:to]
@@ -64,7 +67,7 @@ module Devise
64
67
  template_path
65
68
  end
66
69
 
67
- # Setup a subject doing an I18n lookup. At first, it attempts to set a subject
70
+ # Set up a subject doing an I18n lookup. At first, it attempts to set a subject
68
71
  # based on the current mapping:
69
72
  #
70
73
  # en:
@@ -82,8 +85,8 @@ module Devise
82
85
  # subject: '...'
83
86
  #
84
87
  def subject_for(key)
85
- I18n.t(:"#{devise_mapping.name}_subject", :scope => [:devise, :mailer, key],
86
- :default => [:subject, key.to_s.humanize])
88
+ I18n.t(:"#{devise_mapping.name}_subject", scope: [:devise, :mailer, key],
89
+ default: [:subject, key.to_s.humanize])
87
90
  end
88
91
  end
89
92
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Devise
2
4
  # Responsible for handling devise mappings and routes configuration. Each
3
5
  # resource configured by devise_for in routes is actually creating a mapping
@@ -23,16 +25,18 @@ module Devise
23
25
  #
24
26
  class Mapping #:nodoc:
25
27
  attr_reader :singular, :scoped_path, :path, :controllers, :path_names,
26
- :class_name, :sign_out_via, :format, :used_routes, :used_helpers, :failure_app
28
+ :class_name, :sign_out_via, :format, :used_routes, :used_helpers,
29
+ :failure_app, :router_name
27
30
 
28
31
  alias :name :singular
29
32
 
30
33
  # Receives an object and find a scope for it. If a scope cannot be found,
31
34
  # raises an error. If a symbol is given, it's considered to be the scope.
32
35
  def self.find_scope!(obj)
36
+ obj = obj.devise_scope if obj.respond_to?(:devise_scope)
33
37
  case obj
34
38
  when String, Symbol
35
- return obj
39
+ return obj.to_sym
36
40
  when Class
37
41
  Devise.mappings.each_value { |m| return m.name if obj <= m.to }
38
42
  else
@@ -60,6 +64,8 @@ module Devise
60
64
  @sign_out_via = options[:sign_out_via] || Devise.sign_out_via
61
65
  @format = options[:format]
62
66
 
67
+ @router_name = options[:router_name]
68
+
63
69
  default_failure_app(options)
64
70
  default_controllers(options)
65
71
  default_path_names(options)