ultra-max-kit 0.0.1

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 (114) hide show
  1. checksums.yaml +7 -0
  2. data/devise-5.0.4/CHANGELOG.md +88 -0
  3. data/devise-5.0.4/MIT-LICENSE +21 -0
  4. data/devise-5.0.4/README.md +776 -0
  5. data/devise-5.0.4/app/controllers/devise/confirmations_controller.rb +54 -0
  6. data/devise-5.0.4/app/controllers/devise/omniauth_callbacks_controller.rb +36 -0
  7. data/devise-5.0.4/app/controllers/devise/passwords_controller.rb +88 -0
  8. data/devise-5.0.4/app/controllers/devise/registrations_controller.rb +169 -0
  9. data/devise-5.0.4/app/controllers/devise/sessions_controller.rb +83 -0
  10. data/devise-5.0.4/app/controllers/devise/unlocks_controller.rb +52 -0
  11. data/devise-5.0.4/app/controllers/devise_controller.rb +226 -0
  12. data/devise-5.0.4/app/helpers/devise_helper.rb +5 -0
  13. data/devise-5.0.4/app/mailers/devise/mailer.rb +30 -0
  14. data/devise-5.0.4/app/views/devise/confirmations/new.html.erb +16 -0
  15. data/devise-5.0.4/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  16. data/devise-5.0.4/app/views/devise/mailer/email_changed.html.erb +7 -0
  17. data/devise-5.0.4/app/views/devise/mailer/password_change.html.erb +3 -0
  18. data/devise-5.0.4/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  19. data/devise-5.0.4/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  20. data/devise-5.0.4/app/views/devise/passwords/edit.html.erb +25 -0
  21. data/devise-5.0.4/app/views/devise/passwords/new.html.erb +16 -0
  22. data/devise-5.0.4/app/views/devise/registrations/edit.html.erb +42 -0
  23. data/devise-5.0.4/app/views/devise/registrations/new.html.erb +29 -0
  24. data/devise-5.0.4/app/views/devise/sessions/new.html.erb +26 -0
  25. data/devise-5.0.4/app/views/devise/shared/_error_messages.html.erb +15 -0
  26. data/devise-5.0.4/app/views/devise/shared/_links.html.erb +25 -0
  27. data/devise-5.0.4/app/views/devise/unlocks/new.html.erb +16 -0
  28. data/devise-5.0.4/config/locales/en.yml +65 -0
  29. data/devise-5.0.4/lib/devise/controllers/helpers.rb +295 -0
  30. data/devise-5.0.4/lib/devise/controllers/rememberable.rb +56 -0
  31. data/devise-5.0.4/lib/devise/controllers/responder.rb +35 -0
  32. data/devise-5.0.4/lib/devise/controllers/scoped_views.rb +19 -0
  33. data/devise-5.0.4/lib/devise/controllers/sign_in_out.rb +106 -0
  34. data/devise-5.0.4/lib/devise/controllers/store_location.rb +76 -0
  35. data/devise-5.0.4/lib/devise/controllers/url_helpers.rb +69 -0
  36. data/devise-5.0.4/lib/devise/delegator.rb +18 -0
  37. data/devise-5.0.4/lib/devise/encryptor.rb +24 -0
  38. data/devise-5.0.4/lib/devise/failure_app.rb +287 -0
  39. data/devise-5.0.4/lib/devise/hooks/activatable.rb +12 -0
  40. data/devise-5.0.4/lib/devise/hooks/csrf_cleaner.rb +14 -0
  41. data/devise-5.0.4/lib/devise/hooks/forgetable.rb +11 -0
  42. data/devise-5.0.4/lib/devise/hooks/lockable.rb +9 -0
  43. data/devise-5.0.4/lib/devise/hooks/proxy.rb +23 -0
  44. data/devise-5.0.4/lib/devise/hooks/rememberable.rb +9 -0
  45. data/devise-5.0.4/lib/devise/hooks/timeoutable.rb +35 -0
  46. data/devise-5.0.4/lib/devise/hooks/trackable.rb +11 -0
  47. data/devise-5.0.4/lib/devise/mailers/helpers.rb +87 -0
  48. data/devise-5.0.4/lib/devise/mapping.rb +178 -0
  49. data/devise-5.0.4/lib/devise/models/authenticatable.rb +302 -0
  50. data/devise-5.0.4/lib/devise/models/confirmable.rb +371 -0
  51. data/devise-5.0.4/lib/devise/models/database_authenticatable.rb +204 -0
  52. data/devise-5.0.4/lib/devise/models/lockable.rb +214 -0
  53. data/devise-5.0.4/lib/devise/models/omniauthable.rb +29 -0
  54. data/devise-5.0.4/lib/devise/models/recoverable.rb +156 -0
  55. data/devise-5.0.4/lib/devise/models/registerable.rb +29 -0
  56. data/devise-5.0.4/lib/devise/models/rememberable.rb +158 -0
  57. data/devise-5.0.4/lib/devise/models/timeoutable.rb +45 -0
  58. data/devise-5.0.4/lib/devise/models/trackable.rb +51 -0
  59. data/devise-5.0.4/lib/devise/models/validatable.rb +70 -0
  60. data/devise-5.0.4/lib/devise/models.rb +122 -0
  61. data/devise-5.0.4/lib/devise/modules.rb +30 -0
  62. data/devise-5.0.4/lib/devise/omniauth/config.rb +47 -0
  63. data/devise-5.0.4/lib/devise/omniauth/url_helpers.rb +27 -0
  64. data/devise-5.0.4/lib/devise/omniauth.rb +27 -0
  65. data/devise-5.0.4/lib/devise/orm/active_record.rb +7 -0
  66. data/devise-5.0.4/lib/devise/orm/mongoid.rb +7 -0
  67. data/devise-5.0.4/lib/devise/orm.rb +80 -0
  68. data/devise-5.0.4/lib/devise/parameter_filter.rb +44 -0
  69. data/devise-5.0.4/lib/devise/parameter_sanitizer.rb +172 -0
  70. data/devise-5.0.4/lib/devise/rails/routes.rb +514 -0
  71. data/devise-5.0.4/lib/devise/rails/warden_compat.rb +15 -0
  72. data/devise-5.0.4/lib/devise/rails.rb +57 -0
  73. data/devise-5.0.4/lib/devise/strategies/authenticatable.rb +178 -0
  74. data/devise-5.0.4/lib/devise/strategies/base.rb +22 -0
  75. data/devise-5.0.4/lib/devise/strategies/database_authenticatable.rb +31 -0
  76. data/devise-5.0.4/lib/devise/strategies/rememberable.rb +67 -0
  77. data/devise-5.0.4/lib/devise/test/controller_helpers.rb +156 -0
  78. data/devise-5.0.4/lib/devise/test/integration_helpers.rb +63 -0
  79. data/devise-5.0.4/lib/devise/time_inflector.rb +16 -0
  80. data/devise-5.0.4/lib/devise/token_generator.rb +32 -0
  81. data/devise-5.0.4/lib/devise/version.rb +5 -0
  82. data/devise-5.0.4/lib/devise.rb +533 -0
  83. data/devise-5.0.4/lib/generators/active_record/devise_generator.rb +119 -0
  84. data/devise-5.0.4/lib/generators/active_record/templates/migration.rb +20 -0
  85. data/devise-5.0.4/lib/generators/active_record/templates/migration_existing.rb +27 -0
  86. data/devise-5.0.4/lib/generators/devise/controllers_generator.rb +46 -0
  87. data/devise-5.0.4/lib/generators/devise/devise_generator.rb +28 -0
  88. data/devise-5.0.4/lib/generators/devise/install_generator.rb +42 -0
  89. data/devise-5.0.4/lib/generators/devise/orm_helpers.rb +36 -0
  90. data/devise-5.0.4/lib/generators/devise/views_generator.rb +145 -0
  91. data/devise-5.0.4/lib/generators/mongoid/devise_generator.rb +57 -0
  92. data/devise-5.0.4/lib/generators/templates/README +36 -0
  93. data/devise-5.0.4/lib/generators/templates/controllers/README +14 -0
  94. data/devise-5.0.4/lib/generators/templates/controllers/confirmations_controller.rb +30 -0
  95. data/devise-5.0.4/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +30 -0
  96. data/devise-5.0.4/lib/generators/templates/controllers/passwords_controller.rb +34 -0
  97. data/devise-5.0.4/lib/generators/templates/controllers/registrations_controller.rb +62 -0
  98. data/devise-5.0.4/lib/generators/templates/controllers/sessions_controller.rb +27 -0
  99. data/devise-5.0.4/lib/generators/templates/controllers/unlocks_controller.rb +30 -0
  100. data/devise-5.0.4/lib/generators/templates/devise.rb +316 -0
  101. data/devise-5.0.4/lib/generators/templates/markerb/confirmation_instructions.markerb +5 -0
  102. data/devise-5.0.4/lib/generators/templates/markerb/email_changed.markerb +7 -0
  103. data/devise-5.0.4/lib/generators/templates/markerb/password_change.markerb +3 -0
  104. data/devise-5.0.4/lib/generators/templates/markerb/reset_password_instructions.markerb +8 -0
  105. data/devise-5.0.4/lib/generators/templates/markerb/unlock_instructions.markerb +7 -0
  106. data/devise-5.0.4/lib/generators/templates/simple_form_for/confirmations/new.html.erb +20 -0
  107. data/devise-5.0.4/lib/generators/templates/simple_form_for/passwords/edit.html.erb +27 -0
  108. data/devise-5.0.4/lib/generators/templates/simple_form_for/passwords/new.html.erb +18 -0
  109. data/devise-5.0.4/lib/generators/templates/simple_form_for/registrations/edit.html.erb +35 -0
  110. data/devise-5.0.4/lib/generators/templates/simple_form_for/registrations/new.html.erb +25 -0
  111. data/devise-5.0.4/lib/generators/templates/simple_form_for/sessions/new.html.erb +20 -0
  112. data/devise-5.0.4/lib/generators/templates/simple_form_for/unlocks/new.html.erb +19 -0
  113. data/ultra-max-kit.gemspec +12 -0
  114. metadata +153 -0
@@ -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
@@ -0,0 +1,287 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_controller/metal"
4
+
5
+ module Devise
6
+ # Failure application that will be called every time :warden is thrown from
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.
10
+ class FailureApp < ActionController::Metal
11
+ include ActionController::UrlFor
12
+ include ActionController::Redirecting
13
+
14
+ include Rails.application.routes.url_helpers
15
+ include Rails.application.routes.mounted_helpers
16
+
17
+ include Devise::Controllers::StoreLocation
18
+
19
+ delegate :flash, to: :request
20
+
21
+ include AbstractController::Callbacks
22
+ around_action do |failure_app, action|
23
+ I18n.with_locale(failure_app.i18n_locale, &action)
24
+ end
25
+
26
+ def self.call(env)
27
+ @respond ||= action(:respond)
28
+ @respond.call(env)
29
+ end
30
+
31
+ # Try retrieving the URL options from the parent controller (usually
32
+ # ApplicationController). Instance methods are not supported at the moment,
33
+ # so only the class-level attribute is used.
34
+ def self.default_url_options(*args)
35
+ if defined?(Devise.parent_controller.constantize)
36
+ Devise.parent_controller.constantize.try(:default_url_options) || {}
37
+ else
38
+ {}
39
+ end
40
+ end
41
+
42
+ def respond
43
+ if http_auth?
44
+ http_auth
45
+ elsif warden_options[:recall]
46
+ recall
47
+ else
48
+ redirect
49
+ end
50
+ end
51
+
52
+ def http_auth
53
+ self.status = 401
54
+ self.headers["WWW-Authenticate"] = %(Basic realm=#{Devise.http_authentication_realm.inspect}) if http_auth_header?
55
+ self.content_type = request.format.to_s
56
+ self.response_body = http_auth_body
57
+ end
58
+
59
+ def recall
60
+ header_info = if relative_url_root?
61
+ base_path = Pathname.new(relative_url_root)
62
+ full_path = Pathname.new(attempted_path)
63
+
64
+ { "SCRIPT_NAME" => relative_url_root,
65
+ "PATH_INFO" => '/' + full_path.relative_path_from(base_path).to_s }
66
+ else
67
+ { "PATH_INFO" => attempted_path }
68
+ end
69
+
70
+ header_info.each do | var, value|
71
+ if request.respond_to?(:set_header)
72
+ request.set_header(var, value)
73
+ else
74
+ request.env[var] = value
75
+ end
76
+ end
77
+
78
+ flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
79
+ self.response = recall_app(warden_options[:recall]).call(request.env).tap { |response|
80
+ status = response[0].in?(300..399) ? Devise.responder.redirect_status : Devise.responder.error_status
81
+ # Avoid warnings translating status to code using Rails if available (e.g. `unprocessable_entity` => `unprocessable_content`)
82
+ response[0] = ActionDispatch::Response.try(:rack_status_code, status) || Rack::Utils.status_code(status)
83
+ }
84
+ end
85
+
86
+ def redirect
87
+ store_location!
88
+ if is_flashing_format?
89
+ if flash[:timedout] && flash[:alert]
90
+ flash.keep(:timedout)
91
+ flash.keep(:alert)
92
+ else
93
+ flash[:alert] = i18n_message
94
+ end
95
+ end
96
+ redirect_to redirect_url
97
+ end
98
+
99
+ protected
100
+
101
+ def i18n_options(options)
102
+ options
103
+ end
104
+
105
+ def i18n_message(default = nil)
106
+ message = warden_message || default || :unauthenticated
107
+
108
+ if message.is_a?(Symbol)
109
+ options = {}
110
+ options[:resource_name] = scope
111
+ options[:scope] = "devise.failure"
112
+ options[:default] = [message]
113
+ auth_keys = scope_class.authentication_keys
114
+ human_keys = (auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys).map { |key|
115
+ # TODO: Remove the fallback and just use `downcase_first` once we drop support for Rails 7.0.
116
+ human_key = scope_class.human_attribute_name(key)
117
+ human_key.respond_to?(:downcase_first) ? human_key.downcase_first : human_key[0].downcase + human_key[1..]
118
+ }
119
+ options[:authentication_keys] = human_keys.join(I18n.t(:"support.array.words_connector"))
120
+ options = i18n_options(options)
121
+
122
+ I18n.t(:"#{scope}.#{message}", **options).then { |msg|
123
+ # Ensure that auth keys at the start of the translated string are properly cased.
124
+ msg.start_with?(human_keys.first) ? msg.upcase_first : msg
125
+ }
126
+ else
127
+ message.to_s
128
+ end
129
+ end
130
+
131
+ def i18n_locale
132
+ warden_options[:locale]
133
+ end
134
+
135
+ def redirect_url
136
+ if warden_message == :timeout
137
+ flash[:timedout] = true if is_flashing_format?
138
+
139
+ path = if request.get?
140
+ attempted_path
141
+ else
142
+ extract_path_from_location(request.referrer)
143
+ end
144
+
145
+ path || scope_url
146
+ else
147
+ scope_url
148
+ end
149
+ end
150
+
151
+ def route(scope)
152
+ :"new_#{scope}_session_url"
153
+ end
154
+
155
+ def scope_url
156
+ opts = {}
157
+
158
+ # Initialize script_name with nil to prevent infinite loops in
159
+ # authenticated mounted engines
160
+ opts[:script_name] = nil
161
+
162
+ route = route(scope)
163
+
164
+ opts[:format] = request_format unless skip_format?
165
+
166
+ router_name = Devise.mappings[scope].router_name || Devise.available_router_name
167
+ context = send(router_name)
168
+
169
+ if relative_url_root?
170
+ opts[:script_name] = relative_url_root
171
+ end
172
+
173
+ if context.respond_to?(route)
174
+ context.send(route, opts)
175
+ elsif respond_to?(:root_url)
176
+ root_url(opts)
177
+ else
178
+ "/"
179
+ end
180
+ end
181
+
182
+ def skip_format?
183
+ %w(html */* turbo_stream).include? request_format.to_s
184
+ end
185
+
186
+ # Choose whether we should respond in an HTTP authentication fashion,
187
+ # including 401 and optional headers.
188
+ #
189
+ # This method allows the user to explicitly disable HTTP authentication
190
+ # on AJAX requests in case they want to redirect on failures instead of
191
+ # handling the errors on their own. This is useful in case your AJAX API
192
+ # is the same as your public API and uses a format like JSON (so you
193
+ # cannot mark JSON as a navigational format).
194
+ def http_auth?
195
+ if request.xhr?
196
+ Devise.http_authenticatable_on_xhr
197
+ else
198
+ !(request_format && is_navigational_format?)
199
+ end
200
+ end
201
+
202
+ # It doesn't make sense to send authenticate headers in AJAX requests
203
+ # or if the user disabled them.
204
+ def http_auth_header?
205
+ scope_class.http_authenticatable && !request.xhr?
206
+ end
207
+
208
+ def http_auth_body
209
+ return i18n_message unless request_format
210
+ method = "to_#{request_format}"
211
+ if method == "to_xml"
212
+ { error: i18n_message }.to_xml(root: "errors")
213
+ elsif {}.respond_to?(method)
214
+ { error: i18n_message }.send(method)
215
+ else
216
+ i18n_message
217
+ end
218
+ end
219
+
220
+ def recall_app(app)
221
+ controller, action = app.split("#")
222
+ controller_name = ActiveSupport::Inflector.camelize(controller)
223
+ controller_klass = ActiveSupport::Inflector.constantize("#{controller_name}Controller")
224
+ controller_klass.action(action)
225
+ end
226
+
227
+ def warden
228
+ request.respond_to?(:get_header) ? request.get_header("warden") : request.env["warden"]
229
+ end
230
+
231
+ def warden_options
232
+ request.respond_to?(:get_header) ? request.get_header("warden.options") : request.env["warden.options"]
233
+ end
234
+
235
+ def warden_message
236
+ @message ||= warden.message || warden_options[:message]
237
+ end
238
+
239
+ def scope
240
+ @scope ||= warden_options[:scope] || Devise.default_scope
241
+ end
242
+
243
+ def scope_class
244
+ @scope_class ||= Devise.mappings[scope].to
245
+ end
246
+
247
+ def attempted_path
248
+ warden_options[:attempted_path]
249
+ end
250
+
251
+ # Stores requested URI to redirect the user after signing in. We can't use
252
+ # the scoped session provided by warden here, since the user is not
253
+ # authenticated yet, but we still need to store the URI based on scope, so
254
+ # different scopes would never use the same URI to redirect.
255
+ def store_location!
256
+ store_location_for(scope, attempted_path) if request.get? && !http_auth?
257
+ end
258
+
259
+ def is_navigational_format?
260
+ Devise.navigational_formats.include?(request_format)
261
+ end
262
+
263
+ # Check if flash messages should be emitted. Default is to do it on
264
+ # navigational formats
265
+ def is_flashing_format?
266
+ request.respond_to?(:flash) && is_navigational_format?
267
+ end
268
+
269
+ def request_format
270
+ @request_format ||= request.format.try(:ref)
271
+ end
272
+
273
+ def relative_url_root
274
+ @relative_url_root ||= begin
275
+ config = Rails.application.config
276
+
277
+ config.try(:relative_url_root) || config.action_controller.try(:relative_url_root)
278
+ end
279
+ end
280
+
281
+ def relative_url_root?
282
+ relative_url_root.present?
283
+ end
284
+
285
+ ActiveSupport.run_load_hooks(:devise_failure_app, self)
286
+ end
287
+ end
@@ -0,0 +1,12 @@
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.
6
+ Warden::Manager.after_set_user do |record, warden, options|
7
+ if record && record.respond_to?(:active_for_authentication?) && !record.active_for_authentication?
8
+ scope = options[:scope]
9
+ warden.logout(scope)
10
+ throw :warden, scope: scope, message: record.inactive_message, locale: options.fetch(:locale, I18n.locale)
11
+ end
12
+ end
@@ -0,0 +1,14 @@
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
+ if warden.request.respond_to?(:reset_csrf_token)
8
+ # Rails 7.1+
9
+ warden.request.reset_csrf_token
10
+ else
11
+ warden.request.session.try(:delete, :_csrf_token)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Before logout hook to forget the user in the given scope, if it responds
4
+ # to forget_me! Also clear remember token to ensure the user won't be
5
+ # remembered again. Notice that we forget the user unless the record is not persisted.
6
+ # This avoids forgetting deleted users.
7
+ Warden::Manager.before_logout do |record, warden, options|
8
+ if record.respond_to?(:forget_me!)
9
+ Devise::Hooks::Proxy.new(warden).forget_me(record)
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # After each sign in, if resource responds to failed_attempts, sets it to 0
4
+ # This is only triggered when the user is explicitly set (with set_user)
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!
8
+ end
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
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ Warden::Manager.after_set_user except: :fetch do |record, warden, options|
4
+ scope = options[:scope]
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)
8
+ end
9
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Each time a record is set we check whether its session has already timed out
4
+ # or not, based on last request time. If so, the record is logged out and
5
+ # redirected to the sign in page. Also, each time the request comes and the
6
+ # record is set, we set the last request time inside its scoped session to
7
+ # verify timeout in the following request.
8
+ Warden::Manager.after_set_user do |record, warden, options|
9
+ scope = options[:scope]
10
+ env = warden.request.env
11
+
12
+ if record && record.respond_to?(:timedout?) && warden.authenticated?(scope) &&
13
+ options[:store] != false && !env['devise.skip_timeoutable']
14
+ last_request_at = warden.session(scope)['last_request_at']
15
+
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, locale: options.fetch(:locale, I18n.locale)
29
+ end
30
+
31
+ unless env['devise.skip_trackable']
32
+ warden.session(scope)['last_request_at'] = Time.now.utc.to_i
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # After each sign in, update sign in time, sign in count and sign in IP.
4
+ # This is only triggered when the user is explicitly set (with set_user)
5
+ # and on authentication. Retrieving the user from session (:fetch) does
6
+ # not trigger it.
7
+ Warden::Manager.after_set_user except: :fetch do |record, warden, options|
8
+ if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope]) && !warden.request.env['devise.skip_trackable']
9
+ record.update_tracked_fields!(warden.request)
10
+ end
11
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Devise
4
+ module Mailers
5
+ module Helpers
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ include Devise::Controllers::ScopedViews
10
+ end
11
+
12
+ protected
13
+
14
+ attr_reader :scope_name, :resource
15
+
16
+ # Configure default email options
17
+ def devise_mail(record, action, opts = {}, &block)
18
+ initialize_from_record(record)
19
+ mail headers_for(action, opts), &block
20
+ end
21
+
22
+ def initialize_from_record(record)
23
+ @scope_name = Devise::Mapping.find_scope!(record)
24
+ @resource = instance_variable_set("@#{devise_mapping.name}", record)
25
+ end
26
+
27
+ def devise_mapping
28
+ @devise_mapping ||= Devise.mappings[scope_name]
29
+ end
30
+
31
+ def headers_for(action, opts)
32
+ headers = {
33
+ subject: subject_for(action),
34
+ to: resource.email,
35
+ from: mailer_sender(devise_mapping),
36
+ reply_to: mailer_sender(devise_mapping),
37
+ template_path: template_paths,
38
+ template_name: action
39
+ }
40
+ # Give priority to the mailer's default if they exists.
41
+ headers.delete(:from) if default_params[:from]
42
+ headers.delete(:reply_to) if default_params[:reply_to]
43
+
44
+ headers.merge!(opts)
45
+
46
+ @email = headers[:to]
47
+ headers
48
+ end
49
+
50
+ def mailer_sender(mapping)
51
+ if Devise.mailer_sender.is_a?(Proc)
52
+ Devise.mailer_sender.call(mapping.name)
53
+ else
54
+ Devise.mailer_sender
55
+ end
56
+ end
57
+
58
+ def template_paths
59
+ template_path = _prefixes.dup
60
+ template_path.unshift "#{@devise_mapping.scoped_path}/mailer" if self.class.scoped_views?
61
+ template_path
62
+ end
63
+
64
+ # Set up a subject doing an I18n lookup. At first, it attempts to set a subject
65
+ # based on the current mapping:
66
+ #
67
+ # en:
68
+ # devise:
69
+ # mailer:
70
+ # confirmation_instructions:
71
+ # user_subject: '...'
72
+ #
73
+ # If one does not exist, it fallbacks to ActionMailer default:
74
+ #
75
+ # en:
76
+ # devise:
77
+ # mailer:
78
+ # confirmation_instructions:
79
+ # subject: '...'
80
+ #
81
+ def subject_for(key)
82
+ I18n.t(:"#{devise_mapping.name}_subject", scope: [:devise, :mailer, key],
83
+ default: [:subject, key.to_s.humanize])
84
+ end
85
+ end
86
+ end
87
+ end