Module: Muxi::Webhook
- Defined in:
- lib/muxi/webhook.rb
Defined Under Namespace
Classes: Clarification, ContentItem, ErrorDetails, VerificationError, WebhookEvent
Class Method Summary
collapse
Class Method Details
.parse(payload) ⇒ Object
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# File 'lib/muxi/webhook.rb', line 108
def parse(payload)
data = case payload
when Hash
payload
when String
begin
JSON.parse(payload)
rescue JSON::ParserError => e
raise VerificationError, "Invalid JSON payload: #{e.message}"
end
else
raise VerificationError, "Unsupported payload type: #{payload.class}"
end
WebhookEvent.from_hash(data)
end
|
.secure_compare(a, b) ⇒ Object
125
126
127
128
129
130
131
132
133
|
# File 'lib/muxi/webhook.rb', line 125
def secure_compare(a, b)
return false if a.nil? || b.nil?
return false if a.bytesize != b.bytesize
l = a.unpack("C*")
r = 0
b.each_byte { |v| r |= v ^ l.shift }
r == 0
end
|
.verify_signature(payload, signature_header, secret, tolerance_seconds: 300) ⇒ Object
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
# File 'lib/muxi/webhook.rb', line 76
def verify_signature(payload, , secret, tolerance_seconds: 300)
return false if .nil? || .empty?
raise VerificationError, "Webhook secret is required" if secret.nil? || secret.empty?
begin
parts = .split(",").map { |p| p.split("=", 2) }.to_h
timestamp_str = parts["t"]
signature = parts["v1"]
return false if timestamp_str.nil? || signature.nil?
timestamp = timestamp_str.to_i
rescue StandardError
return false
end
current_time = Time.now.to_i
return false if (current_time - timestamp).abs > tolerance_seconds
payload_bytes = payload.is_a?(String) ? payload : payload.to_s
message = "#{timestamp}.#{payload_bytes}"
expected = OpenSSL::HMAC.hexdigest("SHA256", secret, message)
secure_compare(expected, signature)
end
|