Class: Axn::Webhooks::Outbound::Signer::CustomSigner
- Inherits:
-
Object
- Object
- Axn::Webhooks::Outbound::Signer::CustomSigner
- Defined in:
- lib/axn/webhooks/outbound/signer.rb
Overview
Wraps a user block; called with the same kwargs as the built-in signers, PLUS subscriber:
(PRO-3214, a Subscriber or nil) -- filtered down to whatever the block actually declares
(via CallableArity.accepted_keywords), so a block written against the original
(id:, timestamp:, body:) contract keeps working byte-for-byte rather than raising an
unexpected-keyword ArgumentError the moment a widened caller starts also offering
subscriber:. A block declaring ** receives everything unfiltered.
Constant Summary collapse
- SUPPLIED_KEYWORDS =
The only kwargs a signer is ever called with. A block may ignore any/all of them --
sign { { "X-API-Key" => key } }(zero params) is a legitimate, pre-existing pattern: Ruby blocks are always non-lambda Procs, which silently tolerate being called with kwargs they never declared (Codex P1 finding: an earlier version of this check REQUIRED every block to declare id:/timestamp:/body:, rejecting that working configuration at boot even though it was never actually broken). %i[id timestamp body subscriber].freeze
Instance Method Summary collapse
- #call(id:, timestamp:, body:, subscriber: nil) ⇒ Object
-
#initialize(block) ⇒ CustomSigner
constructor
A new instance of CustomSigner.
Constructor Details
#initialize(block) ⇒ CustomSigner
Returns a new instance of CustomSigner.
48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/axn/webhooks/outbound/signer.rb', line 48 def initialize(block) @block = block @accepted = CallableArity.accepted_keywords(block) # A block declaring NO keywords at all but at least one POSITIONAL param (`sign { |options| # … }`) is the historical "options Hash" shape: Ruby auto-converts trailing keyword # arguments into a Hash for a lone positional parameter (true for both a Proc/block and a # lambda alike), which is exactly what the ORIGINAL unconditional `.call(id:, timestamp:, # body:)` relied on. Filtering down to `**{}` (zero keywords accepted) calls with ZERO # arguments instead -- fine for a Proc (leaves `options` nil, tolerated) but a REQUIRED-arity # lambda raises outright; either way `options` never gets the data (Codex P1 finding). @wants_positional_hash = @accepted != :all && @accepted.empty? && CallableArity.accepts_positional?(block) validate_required_keywords! end |
Instance Method Details
#call(id:, timestamp:, body:, subscriber: nil) ⇒ Object
62 63 64 65 66 67 68 69 70 71 |
# File 'lib/axn/webhooks/outbound/signer.rb', line 62 def call(id:, timestamp:, body:, subscriber: nil) # The positional-Hash shape's CONTRACT is exactly these three keys -- it has no way to # OPT IN to `subscriber:` the way a keyword-declaring block does, so it must never see # it: a pre-existing signer deriving its signature from the WHOLE hash (e.g. hashing # every key-value pair together) would compute a DIFFERENT signature the instant a 4th # key appeared, silently breaking verification on the receiving end (Codex P1 finding). return @block.call({ id:, timestamp:, body: }) if @wants_positional_hash @block.call(**filtered({ id:, timestamp:, body:, subscriber: })) end |