Module: Portage::Ucp::Ap2::MandateGuard

Defined in:
lib/portage/ucp/ap2/mandate_guard.rb

Overview

Mandate validation (design-log §33/Phase B): required fields present, not expired, and — when the caller supplies a trust anchor — cryptographic proof via Ap2::MandateSignature. trusted_keys has no default because this gem has no key infrastructure of its own to default it to (§9's convention: keys are always consumer-provided, never generated or assumed here); a caller that omits it gets shape-only validation, same posture this guard always had, not a silent downgrade. A real PSP adapter is expected to pass the issuing agent's trust anchor (its own store, or a resolver against the agent's own manifest) once it has one. A caller that wants that omission to be an error instead — fail closed rather than silently downgrade to shape-only — sets require_signature: true.

Constant Summary collapse

REQUIRED_FIELDS =
%i[amount currency merchant expires_at signature].freeze

Class Method Summary collapse

Class Method Details

.validate!(mandate, trusted_keys: nil, require_signature: false) ⇒ Object

Parameters:

  • trusted_keys (Array<Hash>, #call, nil) (defaults to: nil) —

    forwarded to Ap2::MandateSignature.verify! when present — see module doc.

  • require_signature (Boolean) (defaults to: false) —

    when true, trusted_keys resolving to nil raises InvalidMandateError instead of falling back to shape-only validation.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/portage/ucp/ap2/mandate_guard.rb', line 26

def self.validate!(mandate, trusted_keys: nil, require_signature: false)
  missing = REQUIRED_FIELDS.reject { |field| mandate.public_send(field) }
  unless missing.empty?
    raise Portage::Ucp::InvalidMandateError,
          "payment mandate is missing required field(s): #{missing.join(', ')}"
  end

  if Time.now >= Time.parse(mandate.expires_at)
    raise Portage::Ucp::InvalidMandateError,
          "payment mandate expired at #{mandate.expires_at}"
  end

  if trusted_keys
    Ap2::MandateSignature.verify!(mandate, trusted_keys: trusted_keys)
  elsif require_signature
    raise Portage::Ucp::InvalidMandateError,
          "payment mandate signature verification is required but no trusted_keys are configured"
  end
end