Module: Spree::WebhookPayloadRedaction

Extended by:
ActiveSupport::Concern
Defined in:
app/models/concerns/spree/webhook_payload_redaction.rb

Overview

Keeps single-use credentials out of the persisted webhook delivery log.

Some events must carry a live credential to their subscriber — a storefront that owns its transactional emails needs the real password reset token to build the email. Delivering it over TLS to a merchant-configured endpoint is intended; keeping a readable copy in spree_webhook_deliveries.payload is not, because that column is queryable and is served back through the Admin API delivery log.

Sensitive values are therefore replaced with REDACTION_PLACEHOLDER before the record is written, and re-attached in memory at send time so the outgoing request body is unchanged.

Constant Summary collapse

SENSITIVE_PAYLOAD_KEYS =

Payload keys under data whose values are live credentials.

%w[reset_token unsubscribe_token verification_token].freeze
REDACTION_PLACEHOLDER =
'[REDACTED]'

Class Method Summary collapse

Class Method Details

.merge(payload, secrets) ⇒ Hash

Re-attaches previously extracted secrets to a redacted payload.

Parameters:

  • payload (Hash)

    the redacted payload

  • secrets (Hash)

    secrets returned by split

Returns:

  • (Hash)

    the payload as it should go over the wire



52
53
54
55
56
57
58
59
60
61
# File 'app/models/concerns/spree/webhook_payload_redaction.rb', line 52

def self.merge(payload, secrets)
  return payload if secrets.blank?

  transform_data_hashes(payload) do |data|
    data.to_h do |key, value|
      secret = secrets[secret_key_for(key)]
      [key, secret.presence || value]
    end
  end
end

.split(payload) ⇒ Array(Hash, Hash)

Splits a payload into the version safe to persist and the secrets held back from it.

Parameters:

  • payload (Hash)

    the full event payload

Returns:

  • (Array(Hash, Hash))

    redacted payload, and the extracted secrets keyed as they appeared under data



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'app/models/concerns/spree/webhook_payload_redaction.rb', line 30

def self.split(payload)
  secrets = {}

  redacted = transform_data_hashes(payload) do |data|
    data.to_h do |key, value|
      if SENSITIVE_PAYLOAD_KEYS.include?(key.to_s) && value.present?
        secrets[secret_key_for(key)] = value
        [key, REDACTION_PLACEHOLDER]
      else
        [key, value]
      end
    end
  end

  secrets.empty? ? [payload, {}] : [redacted, secrets]
end