devise 3.0.0 → 4.8.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 (242) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +351 -0
  3. data/MIT-LICENSE +2 -1
  4. data/README.md +422 -130
  5. data/app/controllers/devise/confirmations_controller.rb +17 -6
  6. data/app/controllers/devise/omniauth_callbacks_controller.rb +12 -6
  7. data/app/controllers/devise/passwords_controller.rb +23 -8
  8. data/app/controllers/devise/registrations_controller.rb +70 -28
  9. data/app/controllers/devise/sessions_controller.rb +49 -17
  10. data/app/controllers/devise/unlocks_controller.rb +11 -4
  11. data/app/controllers/devise_controller.rb +74 -34
  12. data/app/helpers/devise_helper.rb +23 -18
  13. data/app/mailers/devise/mailer.rb +25 -10
  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} +10 -10
  27. data/app/views/devise/unlocks/new.html.erb +9 -5
  28. data/config/locales/en.yml +26 -20
  29. data/lib/devise/controllers/helpers.rb +122 -125
  30. data/lib/devise/controllers/rememberable.rb +14 -14
  31. data/lib/devise/controllers/scoped_views.rb +3 -1
  32. data/lib/devise/controllers/sign_in_out.rb +121 -0
  33. data/lib/devise/controllers/store_location.rb +76 -0
  34. data/lib/devise/controllers/url_helpers.rb +10 -8
  35. data/lib/devise/delegator.rb +2 -0
  36. data/lib/devise/encryptor.rb +24 -0
  37. data/lib/devise/failure_app.rb +132 -42
  38. data/lib/devise/hooks/activatable.rb +7 -6
  39. data/lib/devise/hooks/csrf_cleaner.rb +9 -0
  40. data/lib/devise/hooks/forgetable.rb +3 -1
  41. data/lib/devise/hooks/lockable.rb +5 -3
  42. data/lib/devise/hooks/proxy.rb +23 -0
  43. data/lib/devise/hooks/rememberable.rb +7 -4
  44. data/lib/devise/hooks/timeoutable.rb +18 -8
  45. data/lib/devise/hooks/trackable.rb +3 -1
  46. data/lib/devise/mailers/helpers.rb +15 -18
  47. data/lib/devise/mapping.rb +9 -3
  48. data/lib/devise/models/authenticatable.rb +102 -80
  49. data/lib/devise/models/confirmable.rb +154 -72
  50. data/lib/devise/models/database_authenticatable.rb +125 -25
  51. data/lib/devise/models/lockable.rb +50 -29
  52. data/lib/devise/models/omniauthable.rb +3 -1
  53. data/lib/devise/models/recoverable.rb +72 -50
  54. data/lib/devise/models/registerable.rb +4 -0
  55. data/lib/devise/models/rememberable.rb +65 -32
  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 +6 -13
  60. data/lib/devise/modules.rb +12 -11
  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 +4 -5
  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 +144 -34
  68. data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
  69. data/lib/devise/rails/routes.rb +191 -127
  70. data/lib/devise/rails/warden_compat.rb +2 -1
  71. data/lib/devise/rails.rb +13 -20
  72. data/lib/devise/secret_key_finder.rb +27 -0
  73. data/lib/devise/strategies/authenticatable.rb +21 -22
  74. data/lib/devise/strategies/base.rb +3 -1
  75. data/lib/devise/strategies/database_authenticatable.rb +15 -4
  76. data/lib/devise/strategies/rememberable.rb +15 -3
  77. data/lib/devise/test/controller_helpers.rb +167 -0
  78. data/lib/devise/test/integration_helpers.rb +63 -0
  79. data/lib/devise/test_helpers.rb +7 -123
  80. data/lib/devise/time_inflector.rb +4 -2
  81. data/lib/devise/token_generator.rb +32 -0
  82. data/lib/devise/version.rb +3 -1
  83. data/lib/devise.rb +124 -78
  84. data/lib/generators/active_record/devise_generator.rb +64 -15
  85. data/lib/generators/active_record/templates/migration.rb +9 -8
  86. data/lib/generators/active_record/templates/migration_existing.rb +9 -8
  87. data/lib/generators/devise/controllers_generator.rb +46 -0
  88. data/lib/generators/devise/devise_generator.rb +10 -6
  89. data/lib/generators/devise/install_generator.rb +19 -1
  90. data/lib/generators/devise/orm_helpers.rb +17 -9
  91. data/lib/generators/devise/views_generator.rb +51 -28
  92. data/lib/generators/mongoid/devise_generator.rb +24 -24
  93. data/lib/generators/templates/README +13 -12
  94. data/lib/generators/templates/controllers/README +14 -0
  95. data/lib/generators/templates/controllers/confirmations_controller.rb +30 -0
  96. data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +30 -0
  97. data/lib/generators/templates/controllers/passwords_controller.rb +34 -0
  98. data/lib/generators/templates/controllers/registrations_controller.rb +62 -0
  99. data/lib/generators/templates/controllers/sessions_controller.rb +27 -0
  100. data/lib/generators/templates/controllers/unlocks_controller.rb +30 -0
  101. data/lib/generators/templates/devise.rb +118 -53
  102. data/lib/generators/templates/markerb/confirmation_instructions.markerb +1 -1
  103. data/lib/generators/templates/markerb/email_changed.markerb +7 -0
  104. data/lib/generators/templates/markerb/password_change.markerb +3 -0
  105. data/lib/generators/templates/markerb/reset_password_instructions.markerb +1 -1
  106. data/lib/generators/templates/markerb/unlock_instructions.markerb +1 -1
  107. data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +6 -2
  108. data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +12 -4
  109. data/lib/generators/templates/simple_form_for/passwords/new.html.erb +5 -2
  110. data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +14 -6
  111. data/lib/generators/templates/simple_form_for/registrations/new.html.erb +12 -4
  112. data/lib/generators/templates/simple_form_for/sessions/new.html.erb +11 -6
  113. data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +5 -2
  114. metadata +73 -294
  115. data/.gitignore +0 -10
  116. data/.travis.yml +0 -20
  117. data/.yardopts +0 -9
  118. data/CHANGELOG.rdoc +0 -941
  119. data/CONTRIBUTING.md +0 -14
  120. data/Gemfile +0 -31
  121. data/Gemfile.lock +0 -159
  122. data/Rakefile +0 -35
  123. data/app/views/devise/_links.erb +0 -3
  124. data/devise.gemspec +0 -26
  125. data/devise.png +0 -0
  126. data/gemfiles/Gemfile.rails-3.2.x +0 -31
  127. data/gemfiles/Gemfile.rails-3.2.x.lock +0 -156
  128. data/lib/devise/models/token_authenticatable.rb +0 -89
  129. data/lib/devise/strategies/token_authenticatable.rb +0 -91
  130. data/test/controllers/custom_strategy_test.rb +0 -62
  131. data/test/controllers/helpers_test.rb +0 -253
  132. data/test/controllers/internal_helpers_test.rb +0 -120
  133. data/test/controllers/passwords_controller_test.rb +0 -32
  134. data/test/controllers/sessions_controller_test.rb +0 -99
  135. data/test/controllers/url_helpers_test.rb +0 -59
  136. data/test/delegator_test.rb +0 -19
  137. data/test/devise_test.rb +0 -83
  138. data/test/failure_app_test.rb +0 -221
  139. data/test/generators/active_record_generator_test.rb +0 -73
  140. data/test/generators/devise_generator_test.rb +0 -39
  141. data/test/generators/install_generator_test.rb +0 -13
  142. data/test/generators/mongoid_generator_test.rb +0 -23
  143. data/test/generators/views_generator_test.rb +0 -67
  144. data/test/helpers/devise_helper_test.rb +0 -51
  145. data/test/integration/authenticatable_test.rb +0 -699
  146. data/test/integration/confirmable_test.rb +0 -299
  147. data/test/integration/database_authenticatable_test.rb +0 -84
  148. data/test/integration/http_authenticatable_test.rb +0 -115
  149. data/test/integration/lockable_test.rb +0 -242
  150. data/test/integration/omniauthable_test.rb +0 -133
  151. data/test/integration/recoverable_test.rb +0 -335
  152. data/test/integration/registerable_test.rb +0 -349
  153. data/test/integration/rememberable_test.rb +0 -165
  154. data/test/integration/timeoutable_test.rb +0 -150
  155. data/test/integration/token_authenticatable_test.rb +0 -205
  156. data/test/integration/trackable_test.rb +0 -92
  157. data/test/mailers/confirmation_instructions_test.rb +0 -111
  158. data/test/mailers/reset_password_instructions_test.rb +0 -92
  159. data/test/mailers/unlock_instructions_test.rb +0 -87
  160. data/test/mapping_test.rb +0 -127
  161. data/test/models/authenticatable_test.rb +0 -13
  162. data/test/models/confirmable_test.rb +0 -452
  163. data/test/models/database_authenticatable_test.rb +0 -226
  164. data/test/models/lockable_test.rb +0 -282
  165. data/test/models/omniauthable_test.rb +0 -7
  166. data/test/models/recoverable_test.rb +0 -222
  167. data/test/models/registerable_test.rb +0 -7
  168. data/test/models/rememberable_test.rb +0 -175
  169. data/test/models/serializable_test.rb +0 -49
  170. data/test/models/timeoutable_test.rb +0 -46
  171. data/test/models/token_authenticatable_test.rb +0 -55
  172. data/test/models/trackable_test.rb +0 -13
  173. data/test/models/validatable_test.rb +0 -127
  174. data/test/models_test.rb +0 -163
  175. data/test/omniauth/config_test.rb +0 -57
  176. data/test/omniauth/url_helpers_test.rb +0 -54
  177. data/test/orm/active_record.rb +0 -10
  178. data/test/orm/mongoid.rb +0 -13
  179. data/test/parameter_sanitizer_test.rb +0 -58
  180. data/test/rails_app/Rakefile +0 -6
  181. data/test/rails_app/app/active_record/admin.rb +0 -6
  182. data/test/rails_app/app/active_record/shim.rb +0 -2
  183. data/test/rails_app/app/active_record/user.rb +0 -6
  184. data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -6
  185. data/test/rails_app/app/controllers/admins_controller.rb +0 -11
  186. data/test/rails_app/app/controllers/application_controller.rb +0 -9
  187. data/test/rails_app/app/controllers/home_controller.rb +0 -25
  188. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -2
  189. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -2
  190. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -14
  191. data/test/rails_app/app/controllers/users_controller.rb +0 -31
  192. data/test/rails_app/app/helpers/application_helper.rb +0 -3
  193. data/test/rails_app/app/mailers/users/mailer.rb +0 -12
  194. data/test/rails_app/app/mongoid/admin.rb +0 -29
  195. data/test/rails_app/app/mongoid/shim.rb +0 -23
  196. data/test/rails_app/app/mongoid/user.rb +0 -42
  197. data/test/rails_app/app/views/admins/index.html.erb +0 -1
  198. data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
  199. data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
  200. data/test/rails_app/app/views/home/index.html.erb +0 -1
  201. data/test/rails_app/app/views/home/join.html.erb +0 -1
  202. data/test/rails_app/app/views/home/private.html.erb +0 -1
  203. data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
  204. data/test/rails_app/app/views/layouts/application.html.erb +0 -24
  205. data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
  206. data/test/rails_app/app/views/users/index.html.erb +0 -1
  207. data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
  208. data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
  209. data/test/rails_app/bin/bundle +0 -3
  210. data/test/rails_app/bin/rails +0 -4
  211. data/test/rails_app/bin/rake +0 -4
  212. data/test/rails_app/config/application.rb +0 -40
  213. data/test/rails_app/config/boot.rb +0 -8
  214. data/test/rails_app/config/database.yml +0 -18
  215. data/test/rails_app/config/environment.rb +0 -5
  216. data/test/rails_app/config/environments/development.rb +0 -34
  217. data/test/rails_app/config/environments/production.rb +0 -84
  218. data/test/rails_app/config/environments/test.rb +0 -36
  219. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -7
  220. data/test/rails_app/config/initializers/devise.rb +0 -178
  221. data/test/rails_app/config/initializers/inflections.rb +0 -2
  222. data/test/rails_app/config/initializers/secret_token.rb +0 -8
  223. data/test/rails_app/config/initializers/session_store.rb +0 -1
  224. data/test/rails_app/config/routes.rb +0 -104
  225. data/test/rails_app/config.ru +0 -4
  226. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -74
  227. data/test/rails_app/db/schema.rb +0 -52
  228. data/test/rails_app/lib/shared_admin.rb +0 -14
  229. data/test/rails_app/lib/shared_user.rb +0 -25
  230. data/test/rails_app/public/404.html +0 -26
  231. data/test/rails_app/public/422.html +0 -26
  232. data/test/rails_app/public/500.html +0 -26
  233. data/test/rails_app/public/favicon.ico +0 -0
  234. data/test/routes_test.rb +0 -250
  235. data/test/support/assertions.rb +0 -40
  236. data/test/support/helpers.rb +0 -91
  237. data/test/support/integration.rb +0 -92
  238. data/test/support/locale/en.yml +0 -4
  239. data/test/support/webrat/integrations/rails.rb +0 -24
  240. data/test/test_helper.rb +0 -34
  241. data/test/test_helpers_test.rb +0 -151
  242. data/test/test_models.rb +0 -26
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bcrypt'
4
+
5
+ module Devise
6
+ module Encryptor
7
+ def self.digest(klass, password)
8
+ if klass.pepper.present?
9
+ password = "#{password}#{klass.pepper}"
10
+ end
11
+ ::BCrypt::Password.create(password, cost: klass.stretches).to_s
12
+ end
13
+
14
+ def self.compare(klass, hashed_password, password)
15
+ return false if hashed_password.blank?
16
+ bcrypt = ::BCrypt::Password.new(hashed_password)
17
+ if klass.pepper.present?
18
+ password = "#{password}#{klass.pepper}"
19
+ end
20
+ password = ::BCrypt::Engine.hash_secret(password, bcrypt.salt)
21
+ Devise.secure_compare(password, hashed_password)
22
+ end
23
+ end
24
+ end
@@ -1,28 +1,34 @@
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
 
13
14
  include Rails.application.routes.url_helpers
14
15
  include Rails.application.routes.mounted_helpers
15
16
 
16
- delegate :flash, :to => :request
17
+ include Devise::Controllers::StoreLocation
18
+
19
+ delegate :flash, to: :request
17
20
 
18
21
  def self.call(env)
19
22
  @respond ||= action(:respond)
20
23
  @respond.call(env)
21
24
  end
22
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.
23
29
  def self.default_url_options(*args)
24
- if defined?(ApplicationController)
25
- ApplicationController.default_url_options(*args)
30
+ if defined?(Devise.parent_controller.constantize)
31
+ Devise.parent_controller.constantize.try(:default_url_options) || {}
26
32
  else
27
33
  {}
28
34
  end
@@ -46,30 +52,61 @@ module Devise
46
52
  end
47
53
 
48
54
  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)
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(request.env)
52
75
  end
53
76
 
54
77
  def redirect
55
78
  store_location!
56
- if flash[:timedout] && flash[:alert]
57
- flash.keep(:timedout)
58
- flash.keep(:alert)
59
- else
60
- flash[:alert] = i18n_message
79
+ if is_flashing_format?
80
+ if flash[:timedout] && flash[:alert]
81
+ flash.keep(:timedout)
82
+ flash.keep(:alert)
83
+ else
84
+ flash[:alert] = i18n_message
85
+ end
61
86
  end
62
87
  redirect_to redirect_url
63
88
  end
64
89
 
65
90
  protected
66
91
 
92
+ def i18n_options(options)
93
+ options
94
+ end
95
+
67
96
  def i18n_message(default = nil)
68
97
  message = warden_message || default || :unauthenticated
69
98
 
70
99
  if message.is_a?(Symbol)
71
- I18n.t(:"#{scope}.#{message}", :resource_name => scope,
72
- :scope => "devise.failure", :default => [message])
100
+ options = {}
101
+ options[:resource_name] = scope
102
+ options[:scope] = "devise.failure"
103
+ options[:default] = [message]
104
+ auth_keys = scope_class.authentication_keys
105
+ keys = (auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys).map { |key| scope_class.human_attribute_name(key) }
106
+ options[:authentication_keys] = keys.join(I18n.translate(:"support.array.words_connector"))
107
+ options = i18n_options(options)
108
+
109
+ I18n.t(:"#{scope}.#{message}", **options)
73
110
  else
74
111
  message.to_s
75
112
  end
@@ -77,7 +114,7 @@ module Devise
77
114
 
78
115
  def redirect_url
79
116
  if warden_message == :timeout
80
- flash[:timedout] = true
117
+ flash[:timedout] = true if is_flashing_format?
81
118
 
82
119
  path = if request.get?
83
120
  attempted_path
@@ -85,26 +122,45 @@ module Devise
85
122
  request.referrer
86
123
  end
87
124
 
88
- path || scope_path
125
+ path || scope_url
89
126
  else
90
- scope_path
127
+ scope_url
91
128
  end
92
129
  end
93
130
 
94
- def scope_path
131
+ def route(scope)
132
+ :"new_#{scope}_session_url"
133
+ end
134
+
135
+ def scope_url
95
136
  opts = {}
96
- route = :"new_#{scope}_session_path"
137
+
138
+ # Initialize script_name with nil to prevent infinite loops in
139
+ # authenticated mounted engines in rails 4.2 and 5.0
140
+ opts[:script_name] = nil
141
+
142
+ route = route(scope)
143
+
97
144
  opts[:format] = request_format unless skip_format?
98
145
 
99
- config = Rails.application.config
100
- opts[:script_name] = (config.relative_url_root if config.respond_to?(:relative_url_root))
146
+ router_name = Devise.mappings[scope].router_name || Devise.available_router_name
147
+ context = send(router_name)
148
+
149
+ if relative_url_root?
150
+ opts[:script_name] = relative_url_root
101
151
 
102
- context = send(Devise.available_router_name)
152
+ # We need to add the rootpath to `script_name` manually for applications that use a Rails
153
+ # version lower than 5.1. Otherwise, it is going to generate a wrong path for Engines
154
+ # that use Devise. Remove it when the support of Rails 5.0 is dropped.
155
+ elsif root_path_defined?(context) && !rails_51_and_up?
156
+ rootpath = context.routes.url_helpers.root_path
157
+ opts[:script_name] = rootpath.chomp('/') if rootpath.length > 1
158
+ end
103
159
 
104
160
  if context.respond_to?(route)
105
161
  context.send(route, opts)
106
- elsif respond_to?(:root_path)
107
- root_path(opts)
162
+ elsif respond_to?(:root_url)
163
+ root_url(opts)
108
164
  else
109
165
  "/"
110
166
  end
@@ -114,12 +170,12 @@ module Devise
114
170
  %w(html */*).include? request_format.to_s
115
171
  end
116
172
 
117
- # Choose whether we should respond in a http authentication fashion,
173
+ # Choose whether we should respond in an HTTP authentication fashion,
118
174
  # including 401 and optional headers.
119
175
  #
120
- # This method allows the user to explicitly disable http authentication
121
- # on ajax requests in case they want to redirect on failures instead of
122
- # handling the errors on their own. This is useful in case your ajax API
176
+ # This method allows the user to explicitly disable HTTP authentication
177
+ # on AJAX requests in case they want to redirect on failures instead of
178
+ # handling the errors on their own. This is useful in case your AJAX API
123
179
  # is the same as your public API and uses a format like JSON (so you
124
180
  # cannot mark JSON as a navigational format).
125
181
  def http_auth?
@@ -130,19 +186,19 @@ module Devise
130
186
  end
131
187
  end
132
188
 
133
- # It does not make sense to send authenticate headers in ajax requests
189
+ # It doesn't make sense to send authenticate headers in AJAX requests
134
190
  # or if the user disabled them.
135
191
  def http_auth_header?
136
- Devise.mappings[scope].to.http_authenticatable && !request.xhr?
192
+ scope_class.http_authenticatable && !request.xhr?
137
193
  end
138
194
 
139
195
  def http_auth_body
140
196
  return i18n_message unless request_format
141
197
  method = "to_#{request_format}"
142
198
  if method == "to_xml"
143
- { :error => i18n_message }.to_xml(:root => "errors")
199
+ { error: i18n_message }.to_xml(root: "errors")
144
200
  elsif {}.respond_to?(method)
145
- { :error => i18n_message }.send(method)
201
+ { error: i18n_message }.send(method)
146
202
  else
147
203
  i18n_message
148
204
  end
@@ -156,11 +212,11 @@ module Devise
156
212
  end
157
213
 
158
214
  def warden
159
- env['warden']
215
+ request.respond_to?(:get_header) ? request.get_header("warden") : request.env["warden"]
160
216
  end
161
217
 
162
218
  def warden_options
163
- env['warden.options']
219
+ request.respond_to?(:get_header) ? request.get_header("warden.options") : request.env["warden.options"]
164
220
  end
165
221
 
166
222
  def warden_message
@@ -171,24 +227,58 @@ module Devise
171
227
  @scope ||= warden_options[:scope] || Devise.default_scope
172
228
  end
173
229
 
230
+ def scope_class
231
+ @scope_class ||= Devise.mappings[scope].to
232
+ end
233
+
174
234
  def attempted_path
175
235
  warden_options[:attempted_path]
176
236
  end
177
237
 
178
- # Stores requested uri to redirect the user after signing in. We cannot use
179
- # scoped session provided by warden here, since the user is not authenticated
180
- # yet, but we still need to store the uri based on scope, so different scopes
181
- # would never use the same uri to redirect.
238
+ # Stores requested URI to redirect the user after signing in. We can't use
239
+ # the scoped session provided by warden here, since the user is not
240
+ # authenticated yet, but we still need to store the URI based on scope, so
241
+ # different scopes would never use the same URI to redirect.
182
242
  def store_location!
183
- session["#{scope}_return_to"] = attempted_path if request.get? && !http_auth?
243
+ store_location_for(scope, attempted_path) if request.get? && !http_auth?
184
244
  end
185
245
 
186
246
  def is_navigational_format?
187
247
  Devise.navigational_formats.include?(request_format)
188
248
  end
189
249
 
250
+ # Check if flash messages should be emitted. Default is to do it on
251
+ # navigational formats
252
+ def is_flashing_format?
253
+ request.respond_to?(:flash) && is_navigational_format?
254
+ end
255
+
190
256
  def request_format
191
257
  @request_format ||= request.format.try(:ref)
192
258
  end
259
+
260
+ def relative_url_root
261
+ @relative_url_root ||= begin
262
+ config = Rails.application.config
263
+
264
+ config.try(:relative_url_root) || config.action_controller.try(:relative_url_root)
265
+ end
266
+ end
267
+
268
+ def relative_url_root?
269
+ relative_url_root.present?
270
+ end
271
+
272
+ ActiveSupport.run_load_hooks(:devise_failure_app, self)
273
+
274
+ private
275
+
276
+ def root_path_defined?(context)
277
+ defined?(context.routes) && context.routes.url_helpers.respond_to?(:root_path)
278
+ end
279
+
280
+ def rails_51_and_up?
281
+ Rails.gem_version >= Gem::Version.new("5.1")
282
+ end
193
283
  end
194
284
  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
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ Warden::Manager.after_authentication do |record, warden, options|
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
7
+ warden.request.session.try(:delete, :_csrf_token)
8
+ end
9
+ end
@@ -1,9 +1,11 @@
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.
4
6
  # This avoids forgetting deleted users.
5
7
  Warden::Manager.before_logout do |record, warden, options|
6
8
  if record.respond_to?(:forget_me!)
7
- Devise::Controllers::Rememberable::Proxy.new(warden).forget_me(record)
9
+ Devise::Hooks::Proxy.new(warden).forget_me(record)
8
10
  end
9
11
  end
@@ -1,7 +1,9 @@
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|
4
- if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
5
- record.update_attribute(:failed_attempts, 0) unless record.failed_attempts.zero?
5
+ Warden::Manager.after_set_user except: :fetch do |record, warden, options|
6
+ if record.respond_to?(:reset_failed_attempts!) && warden.authenticated?(options[:scope])
7
+ record.reset_failed_attempts!
6
8
  end
7
9
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Devise
4
+ module Hooks
5
+ # A small warden proxy so we can remember, forget and
6
+ # sign out users from hooks.
7
+ class Proxy #:nodoc:
8
+ include Devise::Controllers::Rememberable
9
+ include Devise::Controllers::SignInOut
10
+
11
+ attr_reader :warden
12
+ delegate :cookies, :request, to: :warden
13
+
14
+ def initialize(warden)
15
+ @warden = warden
16
+ end
17
+
18
+ def session
19
+ warden.request.session
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,6 +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
- if record.respond_to?(:remember_me) && record.remember_me && warden.authenticated?(scope)
4
- Devise::Controllers::Rememberable::Proxy.new(warden).remember_me(record)
5
+ if record.respond_to?(:remember_me) && options[:store] != false &&
6
+ record.remember_me && warden.authenticated?(scope)
7
+ Devise::Hooks::Proxy.new(warden).remember_me(record)
5
8
  end
6
- 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,19 +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
15
 
13
- if record.timedout?(last_request_at) && !env['devise.skip_timeout']
14
- warden.logout(scope)
15
- if record.respond_to?(:expire_auth_token_on_timeout) && record.expire_auth_token_on_timeout
16
- record.reset_authentication_token!
17
- end
18
- throw :warden, :scope => scope, :message => :timeout
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
21
+
22
+ proxy = Devise::Hooks::Proxy.new(warden)
23
+
24
+ if !env['devise.skip_timeout'] &&
25
+ record.timedout?(last_request_at) &&
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
19
29
  end
20
30
 
21
31
  unless env['devise.skip_trackable']
22
- warden.session(scope)['last_request_at'] = Time.now.utc
32
+ warden.session(scope)['last_request_at'] = Time.now.utc.to_i
23
33
  end
24
34
  end
25
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,20 +30,14 @@ 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
- if resource.respond_to?(:headers_for)
39
- ActiveSupport::Deprecation.warn "Calling headers_for in the model is no longer supported. " <<
40
- "Please customize your mailer instead."
41
- headers.merge!(resource.headers_for(action))
42
- end
43
-
44
41
  @email = headers[:to]
45
42
  headers
46
43
  end
@@ -70,7 +67,7 @@ module Devise
70
67
  template_path
71
68
  end
72
69
 
73
- # 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
74
71
  # based on the current mapping:
75
72
  #
76
73
  # en:
@@ -88,8 +85,8 @@ module Devise
88
85
  # subject: '...'
89
86
  #
90
87
  def subject_for(key)
91
- I18n.t(:"#{devise_mapping.name}_subject", :scope => [:devise, :mailer, key],
92
- :default => [:subject, key.to_s.humanize])
88
+ I18n.t(:"#{devise_mapping.name}_subject", scope: [:devise, :mailer, key],
89
+ default: [:subject, key.to_s.humanize])
93
90
  end
94
91
  end
95
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
@@ -42,7 +46,7 @@ module Devise
42
46
  raise "Could not find a valid mapping for #{obj.inspect}"
43
47
  end
44
48
 
45
- def self.find_by_path!(path, path_type=:fullpath)
49
+ def self.find_by_path!(path, path_type = :fullpath)
46
50
  Devise.mappings.each_value { |m| return m if path.include?(m.send(path_type)) }
47
51
  raise "Could not find a valid mapping for path #{path.inspect}"
48
52
  end
@@ -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)