spree_admin 5.5.0.rc1 → 5.5.0.rc2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f4bbbb1dd33ca70b641c0c4c687f4a8a36731ec816c3324930b44139d911bd6
4
- data.tar.gz: d402abe10df4c9fe520db4f9b97fb17e33172238ff7e58b14f71b2754a9c09a5
3
+ metadata.gz: cf50ce30e9bb9efb5d77bfc984d87f921c997520125e78b375c375d391999aec
4
+ data.tar.gz: 8bbc5de5e700786db47adc040e6e048901503bb9572d382302336d33a7531866
5
5
  SHA512:
6
- metadata.gz: 9931e85d7ade12bc71fd556f9014cb410ad03e205eedc6ba4c1bc03d3e5d38a32ddabd7a5b34114fe0cb1b58059d7b6ce36907c3515a866812609c9911989517
7
- data.tar.gz: 8f9090d2f5d25c761f4f3ce74701fabd179b9947c21ce23ab64362ac67363ce77b63c624136a35bb02b2897d60fe72e716ac4e8539fdc032f5bc7c7cdbcab12c
6
+ metadata.gz: 3dd8c8013f072e443fb99b2c70450f005904f0d738870dcf6182e4edd39810fb462e6869eea08cc0ebc235d2d55895750469eaff710b4958fd86880952108aff
7
+ data.tar.gz: d032bec7f6a7f7eee57054a1b4af6e36e19fca1b80ef276c9a95eb71d6451151c629e05446426893cf1fae120b52a97e9863eafc2644ef2b1a2ac65475030d59
@@ -0,0 +1,58 @@
1
+ module Spree
2
+ module Admin
3
+ module AuthRateLimiting
4
+ extend ActiveSupport::Concern
5
+
6
+ class_methods do
7
+ # @param limit_preference [Symbol] e.g. :rate_limit_login / :rate_limit_password_reset
8
+ # @param redirect_to [Proc] evaluated in controller context to the path to bounce
9
+ # back to when rate limited, e.g. `-> { new_session_path(resource_name) }`.
10
+ # @return [void]
11
+ def auth_rate_limit(limit_preference, redirect_to:)
12
+ limit = Spree::Admin::RuntimeConfig[limit_preference] || 5
13
+ window = (Spree::Admin::RuntimeConfig[:rate_limit_window] || 60).seconds
14
+ prefix = limit_preference.to_s # unique namespace per controller/action
15
+
16
+ # By IP — always present; backstops blank-email floods.
17
+ rate_limit(
18
+ to: limit,
19
+ within: window,
20
+ by: -> { "#{prefix}-ip:#{request.remote_ip}" },
21
+ with: -> { admin_auth_rate_limit_response(redirect_to) },
22
+ store: Rails.cache,
23
+ only: :create
24
+ )
25
+
26
+ # By submitted email (case-insensitive). Falls back to per-IP bucketing when
27
+ # the email is blank, so blank submissions don't all share one global bucket.
28
+ rate_limit(
29
+ to: limit,
30
+ within: window,
31
+ by: lambda {
32
+ email = admin_auth_rate_limit_email
33
+ email.present? ? "#{prefix}-email:#{email}" : "#{prefix}-email-ip:#{request.remote_ip}"
34
+ },
35
+ with: -> { admin_auth_rate_limit_response(redirect_to) },
36
+ store: Rails.cache,
37
+ only: :create
38
+ )
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ # Email is read via Devise's `resource_params` so it works regardless of the
45
+ # configured admin user class / resource param key.
46
+ def admin_auth_rate_limit_email
47
+ resource_params[:email].to_s.strip.downcase.presence
48
+ rescue StandardError
49
+ nil
50
+ end
51
+
52
+ def admin_auth_rate_limit_response(redirect_path)
53
+ flash[:alert] = I18n.t('devise.failure.too_many_attempts')
54
+ redirect_to instance_exec(&redirect_path)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,8 +1,12 @@
1
1
  module Spree
2
2
  module Admin
3
3
  class UserPasswordsController < defined?(Devise::PasswordsController) ? Devise::PasswordsController : Spree::Admin::BaseController
4
+ include Spree::Admin::AuthRateLimiting
5
+
4
6
  layout 'spree/minimal'
5
7
 
8
+ auth_rate_limit :rate_limit_password_reset, redirect_to: -> { new_password_path(resource_name) }
9
+
6
10
  def create
7
11
  self.resource = resource_class.send_reset_password_instructions(resource_params)
8
12
  yield resource if block_given?
@@ -1,8 +1,12 @@
1
1
  module Spree
2
2
  module Admin
3
3
  class UserSessionsController < defined?(Devise::SessionsController) ? Devise::SessionsController : Spree::Admin::BaseController
4
+ include Spree::Admin::AuthRateLimiting
5
+
4
6
  layout 'spree/minimal'
5
7
 
8
+ auth_rate_limit :rate_limit_login, redirect_to: -> { new_session_path(resource_name) }
9
+
6
10
  # We need to overwrite this action because `return_to` url may be in a different domain
7
11
  # So we need to pass `allow_other_host` option to `redirect_to` method
8
12
  def create
@@ -101,7 +101,7 @@
101
101
  <%= render 'spree/admin/shared/index_table_options', collection: @products %>
102
102
  </div>
103
103
  <% else %>
104
- <%= render 'spree/admin/shared/no_resource_found', new_object_url: nil %>
104
+ <%= render 'spree/admin/shared/no_resource_found', new_object_url: nil, model_class: Spree::Product %>
105
105
  <% end %>
106
106
  </div>
107
107
  </div>
@@ -17,6 +17,11 @@ module Spree
17
17
  preference :legacy_sidebar_navigation, :boolean, default: false
18
18
 
19
19
  preference :reports_line_items_limit, :integer, default: 1000
20
+
21
+ # Brute-force rate limiting for the admin dashboard auth endpoints (login / password reset).
22
+ preference :rate_limit_window, :integer, default: 60 # window in seconds
23
+ preference :rate_limit_login, :integer, default: 5 # per IP and per email
24
+ preference :rate_limit_password_reset, :integer, default: 3 # per IP and per email
20
25
  end
21
26
  end
22
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.5.0.rc1
4
+ version: 5.5.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vendo Connect Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-10 00:00:00.000000000 Z
11
+ date: 2026-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: spree
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 5.5.0.rc1
19
+ version: 5.5.0.rc2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 5.5.0.rc1
26
+ version: 5.5.0.rc2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: active_link_to
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -284,6 +284,7 @@ files:
284
284
  - app/assets/tailwind/spree/admin/views/_dashboard.css
285
285
  - app/assets/tailwind/spree/admin/views/_page-builder.css
286
286
  - app/controllers/concerns/spree/admin/analytics_concern.rb
287
+ - app/controllers/concerns/spree/admin/auth_rate_limiting.rb
287
288
  - app/controllers/concerns/spree/admin/breadcrumb_concern.rb
288
289
  - app/controllers/concerns/spree/admin/bulk_operations_concern.rb
289
290
  - app/controllers/concerns/spree/admin/order_breadcrumb_concern.rb
@@ -1171,9 +1172,9 @@ licenses:
1171
1172
  - BSD-3-Clause
1172
1173
  metadata:
1173
1174
  bug_tracker_uri: https://github.com/spree/spree/issues
1174
- changelog_uri: https://github.com/spree/spree/releases/tag/v5.5.0.rc1
1175
+ changelog_uri: https://github.com/spree/spree/releases/tag/v5.5.0.rc2
1175
1176
  documentation_uri: https://docs.spreecommerce.org/
1176
- source_code_uri: https://github.com/spree/spree/tree/v5.5.0.rc1
1177
+ source_code_uri: https://github.com/spree/spree/tree/v5.5.0.rc2
1177
1178
  post_install_message:
1178
1179
  rdoc_options: []
1179
1180
  require_paths: