Module: Axn::Webhooks::Verifiers

Defined in:
lib/axn/webhooks/verifiers.rb,
lib/axn/webhooks/verifiers/hmac.rb,
lib/axn/webhooks/verifiers/basic_auth.rb,
lib/axn/webhooks/verifiers/standard_webhooks.rb

Overview

Builds a verifier callable (->(request){ Boolean }) from a verify declaration. A custom block is used verbatim; a strategy symbol is looked up in STRATEGIES (populated by verifiers/*.rb).

Defined Under Namespace

Modules: StandardWebhooks Classes: BasicAuth

Constant Summary collapse

STRATEGIES =

rubocop:disable Style/MutableConstant

{}

Class Method Summary collapse

Class Method Details

.build(strategy:, opts:, block:) ⇒ Object



40
41
42
43
44
45
46
47
# File 'lib/axn/webhooks/verifiers.rb', line 40

def build(strategy:, opts:, block:)
  return block if block

  builder = STRATEGIES.fetch(strategy&.to_sym) do
    raise Axn::Webhooks::Error, "unknown verify strategy #{strategy.inspect}"
  end
  builder.call(**opts)
end

.register(name, &builder) ⇒ Object



13
# File 'lib/axn/webhooks/verifiers.rb', line 13

def register(name, &builder) = STRATEGIES[name.to_sym] = builder

.require_secret!(declaration, value, label: "secret", error: Axn::Webhooks::Error) ⇒ Object

THE shared secret guard. Every strategy in this gem routes its secret/credential through here, in both directions, so a new strategy cannot quietly reintroduce the bug this exists for — which has now recurred four times, each fix having been applied only where it was noticed (literal whsec_, resolved whsec_, verify :hmac, verify :basic_auth).

The bug: a blank or absent secret is not a failure, it is a WEAK KEY. "" is a perfectly legal HMAC key, so an empty secret makes the expected signature a value any stranger can compute — an authentication bypass, not a mismatch. nil happens to fail closed only by accident (OpenSSL raises TypeError on it), which is precisely why checking nil alone gives false confidence.

Raises rather than returning false: a 401 meaning "we are misconfigured" is indistinguishable from one meaning "you are not the vendor", and would otherwise present as an unexplained outage. Names the value's TYPE or emptiness only — never its bytes, since this can fire on every request and would otherwise flow the live credential into logs and error trackers. error: follows this gem's misconfiguration split: ArgumentError for a DECLARATION mistake caught at boot, Axn::Webhooks::Error for a value that only goes bad at request time.

Raises:

  • (error)


32
33
34
35
36
37
38
# File 'lib/axn/webhooks/verifiers.rb', line 32

def require_secret!(declaration, value, label: "secret", error: Axn::Webhooks::Error)
  return value if value.is_a?(String) && !value.empty?

  raise error,
        "#{declaration} #{label} must be a non-empty String " \
        "(got #{value.is_a?(String) ? 'an empty String' : value.class})"
end