spree_api 5.4.2 → 5.4.4

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: 4b295d2c49585c2fd0368b2b31bb782e19b77af7c4580e243896257151f5fd47
4
- data.tar.gz: fea6f271b52ec0218ab2991e4bdaaa496d465a1fc2af7ada90bfee238de2216a
3
+ metadata.gz: 60cd4bf73d495ad9c5070f9c589f0e2d7bc4403ea35d01d79f3d00c2208fde26
4
+ data.tar.gz: 5e0517af8dee47eb2c69b465050ddf2db9309bde1130540caa440c076773cfc9
5
5
  SHA512:
6
- metadata.gz: d256c6250da995fd8762ed02f924e0d8f4c97fc3f39c3d94c9fc21b43b2d1878da871c0baff222e33d8d5c42b043878f6ec6aeea7baee6e3963fadb7bc6449b4
7
- data.tar.gz: 4c30eff24e0d890cc2cb967e7f6cb0c476783324ea9724d46dc4fb3532bcd37400e81d07640e1e3b764e283ca3bf23c7f3148d7183060eb47b94ce238c129775
6
+ metadata.gz: 2db9f9ca93c76a1a195219c5af06abcce880cb538d517982700836e9b973b992d14e8ac9c6d77249787fff658410f243e84cdf3b4cd885f376d46e3f03501148
7
+ data.tar.gz: be380eaca399b016e832c5af98985c3183c34a1a8f9d83b8f1354bd9403287e1cc0a22fffabf1f82a05f553c15f34fcc4baf6b339199dfef74b7edeb60cd65e9
@@ -82,10 +82,15 @@ module Spree
82
82
  end
83
83
 
84
84
  # PATCH /api/v3/store/carts/:id/associate
85
- # Associates a guest cart with the currently authenticated user
86
- # Requires: JWT authentication + cart ID in URL
85
+ # Associates a guest cart with the currently authenticated user.
86
+ # Requires: JWT authentication + cart ID in URL + possession of the
87
+ # cart's token (x-spree-token). The token is the credential that
88
+ # authorizes claiming the cart, so it is required even when the cart
89
+ # is already the caller's own.
87
90
  def associate
88
91
  @cart = find_cart_for_association
92
+ authorize!(:update, @cart, cart_token)
93
+ require_cart_token!
89
94
 
90
95
  result = Spree.cart_associate_service.call(guest_order: @cart, user: current_user, guest_only: true)
91
96
 
@@ -172,6 +177,14 @@ module Spree
172
177
  def find_cart_for_association
173
178
  current_store.carts.where(user: [nil, current_user]).find_by_prefix_id!(params[:id])
174
179
  end
180
+
181
+ # Claiming a cart requires presenting its token, even when the caller
182
+ # already owns it — the token, not ownership, is the claim credential.
183
+ def require_cart_token!
184
+ valid = cart_token.present? && cart_token == @cart.token
185
+
186
+ raise CanCan::AccessDenied.new(nil, :update, @cart) unless valid
187
+ end
175
188
  end
176
189
  end
177
190
  end
@@ -8,10 +8,15 @@ module Spree
8
8
 
9
9
  # Accept optional second argument for backward compatibility with jobs
10
10
  # enqueued before this change was deployed.
11
- def perform(delivery_id, _deprecated_secret_key = nil)
11
+ #
12
+ # `payload_secrets` carries credentials withheld from the persisted payload
13
+ # so the outgoing request body stays complete. See
14
+ # {Spree::WebhookPayloadRedaction}.
15
+ def perform(delivery_id, _deprecated_secret_key = nil, payload_secrets: nil)
12
16
  delivery = Spree::WebhookDelivery.find_by(id: delivery_id)
13
17
  return if delivery.nil?
14
18
 
19
+ delivery.payload_secrets = payload_secrets
15
20
  secret_key = delivery.webhook_endpoint.secret_key
16
21
  Spree::Webhooks::DeliverWebhook.call(delivery: delivery, secret_key: secret_key)
17
22
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Api
5
+ module V3
6
+ module Admin
7
+ # Admin API serializer for {Spree::WebhookDelivery}.
8
+ #
9
+ # Surface the delivery log so admins can audit + retry failed webhook
10
+ # attempts. Includes the request payload + response body so they can
11
+ # inspect what was sent and what the endpoint returned.
12
+ class WebhookDeliverySerializer < V3::BaseSerializer
13
+ typelize event_name: :string,
14
+ event_id: [:string, nullable: true],
15
+ response_code: [:number, nullable: true],
16
+ execution_time: [:number, nullable: true],
17
+ error_type: [:string, nullable: true],
18
+ request_errors: [:string, nullable: true],
19
+ response_body: [:string, nullable: true],
20
+ success: [:boolean, nullable: true],
21
+ delivered_at: [:string, nullable: true],
22
+ payload: 'Record<string, unknown>',
23
+ webhook_endpoint_id: :string,
24
+ webhook_endpoint_url: :string
25
+
26
+ attributes :event_name, :event_id, :response_code, :execution_time,
27
+ :error_type, :request_errors, :response_body, :success,
28
+ created_at: :iso8601, updated_at: :iso8601,
29
+ delivered_at: :iso8601
30
+
31
+ # Redacted again on read: deliveries written before payload redaction
32
+ # shipped still hold live credentials in the column.
33
+ attribute :payload do |delivery|
34
+ Spree::WebhookPayloadRedaction.split(delivery.payload).first
35
+ end
36
+
37
+ attribute :webhook_endpoint_id do |delivery|
38
+ delivery.webhook_endpoint&.prefixed_id
39
+ end
40
+
41
+ # Delegated from the parent endpoint — saves callers from having to
42
+ # join the endpoint payload to show "where did this delivery go?".
43
+ attribute :webhook_endpoint_url do |delivery|
44
+ delivery.webhook_endpoint&.url
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -56,7 +56,7 @@ module Spree
56
56
  end
57
57
 
58
58
  attribute :tags do |product|
59
- product.taggings.map(&:tag)
59
+ product.tags.map(&:name) # not pluck as we preload tags
60
60
  end
61
61
 
62
62
  # Price object - calculated price with price list resolution
@@ -56,7 +56,7 @@ module Spree
56
56
  'X-Spree-Webhook-Timestamp' => webhook_timestamp.to_s,
57
57
  'X-Spree-Webhook-Event' => @delivery.event_name
58
58
  }
59
- body = @delivery.payload.to_json
59
+ body = payload_json
60
60
  http_options = { open_timeout: TIMEOUT, read_timeout: TIMEOUT, verify_mode: ssl_verify_mode }
61
61
 
62
62
  # SSRF protection is disabled in development so webhooks can reach
@@ -77,10 +77,14 @@ module Spree
77
77
  end
78
78
 
79
79
  def generate_signature
80
- payload_json = @delivery.payload.to_json
81
80
  OpenSSL::HMAC.hexdigest('SHA256', @secret_key, "#{webhook_timestamp}.#{payload_json}")
82
81
  end
83
82
 
83
+ # Memoized so the signature is computed over exactly the bytes sent.
84
+ def payload_json
85
+ @payload_json ||= @delivery.deliverable_payload.to_json
86
+ end
87
+
84
88
  def webhook_timestamp
85
89
  @webhook_timestamp ||= Time.current.to_i
86
90
  end
@@ -50,13 +50,16 @@ module Spree
50
50
  )
51
51
  end
52
52
 
53
+ # Live credentials go over the wire but never into the delivery log.
54
+ persisted_payload, secrets = Spree::WebhookPayloadRedaction.split(payload)
55
+
53
56
  delivery = endpoint.webhook_deliveries.create!(
54
57
  event_name: event.name,
55
58
  event_id: event.id,
56
- payload: payload
59
+ payload: persisted_payload
57
60
  )
58
61
 
59
- Spree::WebhookDeliveryJob.perform_later(delivery.id)
62
+ Spree::WebhookDeliveryJob.perform_later(delivery.id, payload_secrets: secrets)
60
63
  rescue ActiveRecord::RecordNotUnique
61
64
  # Race condition: another thread already created this delivery — safe to ignore
62
65
  rescue StandardError => e
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.4.2
4
+ version: 5.4.4
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-04-27 00:00:00.000000000 Z
11
+ date: 2026-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rswag-specs
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 5.4.2
75
+ version: 5.4.4
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 5.4.2
82
+ version: 5.4.4
83
83
  description: Spree's API
84
84
  email:
85
85
  - hello@spreecommerce.org
@@ -180,6 +180,7 @@ files:
180
180
  - app/serializers/spree/api/v3/admin/store_credit_serializer.rb
181
181
  - app/serializers/spree/api/v3/admin/tax_category_serializer.rb
182
182
  - app/serializers/spree/api/v3/admin/variant_serializer.rb
183
+ - app/serializers/spree/api/v3/admin/webhook_delivery_serializer.rb
183
184
  - app/serializers/spree/api/v3/asset_serializer.rb
184
185
  - app/serializers/spree/api/v3/base_serializer.rb
185
186
  - app/serializers/spree/api/v3/cart_serializer.rb
@@ -263,9 +264,9 @@ licenses:
263
264
  - BSD-3-Clause
264
265
  metadata:
265
266
  bug_tracker_uri: https://github.com/spree/spree/issues
266
- changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.2
267
+ changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.4
267
268
  documentation_uri: https://docs.spreecommerce.org/
268
- source_code_uri: https://github.com/spree/spree/tree/v5.4.2
269
+ source_code_uri: https://github.com/spree/spree/tree/v5.4.4
269
270
  post_install_message:
270
271
  rdoc_options: []
271
272
  require_paths: