Module: Airwallex::Webhook

Defined in:
lib/airwallex/webhook.rb

Constant Summary collapse

MILLISECONDS_THRESHOLD =
1_000_000_000_000

Class Method Summary collapse

Class Method Details

.construct_event(payload:, signature:, timestamp:, secret:, tolerance: 300) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/airwallex/webhook.rb', line 12

def construct_event(payload:, signature:, timestamp:, secret:, tolerance: 300)
  verify_signature!(
    payload: payload,
    signature: signature,
    timestamp: timestamp,
    secret: secret,
    tolerance: tolerance
  )

  JSON.parse(payload)
rescue JSON::ParserError
  raise InvalidResponseError, "Invalid webhook payload"
end

.secure_compare(a, b) ⇒ Object



51
52
53
54
55
56
57
58
# File 'lib/airwallex/webhook.rb', line 51

def secure_compare(a, b)
  return false unless a.bytesize == b.bytesize

  l = a.unpack "C#{a.bytesize}"
  res = 0
  b.each_byte { |byte| res |= byte ^ l.shift }
  res.zero?
end

.verify_signature(payload:, signature:, timestamp:, secret:, tolerance: 300) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
# File 'lib/airwallex/webhook.rb', line 26

def verify_signature(payload:, signature:, timestamp:, secret:, tolerance: 300)
  verify_signature!(
    payload: payload,
    signature: signature,
    timestamp: timestamp,
    secret: secret,
    tolerance: tolerance
  )

  true
end

.verify_signature!(payload:, signature:, timestamp:, secret:, tolerance: 300) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/airwallex/webhook.rb', line 38

def verify_signature!(payload:, signature:, timestamp:, secret:, tolerance: 300)
  validate_inputs!(payload, signature, timestamp, secret, tolerance)

  normalized_timestamp = normalize_timestamp!(timestamp)
  validate_timestamp_tolerance!(normalized_timestamp, tolerance)

  expected_signature = compute_signature(timestamp, payload, secret)

  raise WebhookSignatureError, "Invalid signature" unless secure_compare(expected_signature, signature.to_s)

  true
end