spree_admin 5.5.0.rc1 → 5.5.0.rc3
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 +4 -4
- data/app/controllers/concerns/spree/admin/auth_rate_limiting.rb +58 -0
- data/app/controllers/spree/admin/api_keys_controller.rb +5 -4
- data/app/controllers/spree/admin/user_passwords_controller.rb +4 -0
- data/app/controllers/spree/admin/user_sessions_controller.rb +4 -0
- data/app/views/spree/admin/api_keys/_form.html.erb +31 -15
- data/app/views/spree/admin/product_translations/index.html.erb +1 -1
- data/config/locales/en.yml +1 -0
- data/lib/spree/admin/runtime_configuration.rb +5 -0
- metadata +7 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aeccd346505aa57fc41defc8eeaf544748167ea25808680cf7b4071ca5404bf5
|
|
4
|
+
data.tar.gz: 74f389f5a27205ba33b7a3b796463a0649f1ce5925aac036353e2aabd00d2594
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8eb54e03b82a3cbd05549fbd8cf4d1902610fe1e7179608374ce0544f2c4364f274bd23a70da5e6b78bcec4cb072731523a305cb49166199143fa74585cca98d
|
|
7
|
+
data.tar.gz: 9d60a5a4842dd23af84e986858497f8ab2b93bd1b7f29ac939b40fea952d3fa44e437c3a1ca709024003c72fda4d7e771e9bc316d20618e1fa558001bea730c8
|
|
@@ -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
|
|
@@ -51,10 +51,11 @@ module Spree
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def permitted_resource_params
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
# `key_type` and `scopes` are create-only (scope immutability lives on
|
|
55
|
+
# Spree::ApiKey); only the human-facing `name` is editable afterward.
|
|
56
|
+
return params.require(:api_key).permit(:name) unless action_name == 'create'
|
|
57
|
+
|
|
58
|
+
params.require(:api_key).permit(permitted_api_key_attributes)
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
def location_after_save
|
|
@@ -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
|
|
@@ -25,20 +25,36 @@
|
|
|
25
25
|
</div>
|
|
26
26
|
</div>
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
<div class="card-
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
<% if f.object.new_record? %>
|
|
29
|
+
<div class="card mb-6" id="api-key-scopes" data-secret-only data-show-when-key-type="secret">
|
|
30
|
+
<div class="card-header">
|
|
31
|
+
<h5 class="card-title"><%= Spree.t('admin.api_keys.scopes', default: 'Scopes') %></h5>
|
|
32
|
+
<p class="text-sm text-gray-500 mt-1">
|
|
33
|
+
<%= Spree.t('admin.api_keys.scopes_description', default: 'Required for secret keys. Pick the narrowest set of scopes your integration needs.') %>
|
|
34
|
+
</p>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="card-body">
|
|
37
|
+
<% Spree::ApiKey::SCOPES.each do |scope| %>
|
|
38
|
+
<div class="custom-control form-checkbox mb-1">
|
|
39
|
+
<%= f.check_box :scopes, { multiple: true, class: 'custom-control-input', id: "api_key_scopes_#{scope}" }, scope, nil %>
|
|
40
|
+
<%= f.label "scopes_#{scope}", scope, class: 'custom-control-label font-mono text-sm' %>
|
|
41
|
+
</div>
|
|
42
|
+
<% end %>
|
|
43
|
+
<%= f.hidden_field :scopes, value: '', multiple: true %>
|
|
44
|
+
</div>
|
|
34
45
|
</div>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
<% elsif f.object.secret? %>
|
|
47
|
+
<div class="card mb-6">
|
|
48
|
+
<div class="card-header">
|
|
49
|
+
<h5 class="card-title"><%= Spree.t('admin.api_keys.scopes', default: 'Scopes') %></h5>
|
|
50
|
+
<p class="text-sm text-gray-500 mt-1">
|
|
51
|
+
<%= Spree.t('admin.api_keys.scopes_immutable', default: 'Scopes are fixed when the key is created. To change them, create a new key with the scopes you need and revoke this one.') %>
|
|
52
|
+
</p>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="card-body">
|
|
55
|
+
<% f.object.scopes.each do |scope| %>
|
|
56
|
+
<span class="badge badge-light font-mono text-sm me-1 mb-1"><%= scope %></span>
|
|
57
|
+
<% end %>
|
|
58
|
+
</div>
|
|
43
59
|
</div>
|
|
44
|
-
|
|
60
|
+
<% end %>
|
|
@@ -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>
|
data/config/locales/en.yml
CHANGED
|
@@ -28,6 +28,7 @@ en:
|
|
|
28
28
|
revoked_by: Revoked by
|
|
29
29
|
scopes: Scopes
|
|
30
30
|
scopes_description: Required for secret keys. Pick the narrowest set of scopes your integration needs.
|
|
31
|
+
scopes_immutable: Scopes are fixed when the key is created. To change them, create a new key with the scopes you need and revoke this one.
|
|
31
32
|
secret_key_hidden: This secret key cannot be revealed. If you've lost it, revoke this key and create a new one.
|
|
32
33
|
statuses:
|
|
33
34
|
active: Active
|
|
@@ -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.
|
|
4
|
+
version: 5.5.0.rc3
|
|
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-
|
|
11
|
+
date: 2026-06-18 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.
|
|
19
|
+
version: 5.5.0.rc3
|
|
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.
|
|
26
|
+
version: 5.5.0.rc3
|
|
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.
|
|
1175
|
+
changelog_uri: https://github.com/spree/spree/releases/tag/v5.5.0.rc3
|
|
1175
1176
|
documentation_uri: https://docs.spreecommerce.org/
|
|
1176
|
-
source_code_uri: https://github.com/spree/spree/tree/v5.5.0.
|
|
1177
|
+
source_code_uri: https://github.com/spree/spree/tree/v5.5.0.rc3
|
|
1177
1178
|
post_install_message:
|
|
1178
1179
|
rdoc_options: []
|
|
1179
1180
|
require_paths:
|