Class: Reattract::Webhook
- Inherits:
-
Object
- Object
- Reattract::Webhook
- Defined in:
- lib/reattract/webhook.rb
Overview
Reattract’s webhook verification class
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(secret) ⇒ Webhook
constructor
A new instance of Webhook.
- #sign(msgId, timestamp, payload) ⇒ Object
- #verify(payload, headers) ⇒ Object
Constructor Details
#initialize(secret) ⇒ Webhook
Returns a new instance of Webhook.
11 12 13 14 15 16 17 |
# File 'lib/reattract/webhook.rb', line 11 def initialize(secret) if secret.start_with?(SECRET_PREFIX) secret = secret[SECRET_PREFIX.length..-1] end @secret = Base64.decode64(secret) end |
Class Method Details
.new_using_raw_bytes(secret) ⇒ Object
7 8 9 |
# File 'lib/reattract/webhook.rb', line 7 def self.new_using_raw_bytes(secret) self.new(secret.pack("C*").force_encoding("UTF-8")) end |
Instance Method Details
#sign(msgId, timestamp, payload) ⇒ Object
49 50 51 52 53 54 55 56 57 58 |
# File 'lib/reattract/webhook.rb', line 49 def sign(msgId, , payload) begin now = Integer() rescue raise WebhookSigningError, "Invalid timestamp" end toSign = "#{msgId}.#{}.#{payload}" signature = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new("sha256"), @secret, toSign)).strip return "v1,#{signature}" end |
#verify(payload, headers) ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/reattract/webhook.rb', line 19 def verify(payload, headers) msgId = headers["svix-id"] msgSignature = headers["svix-signature"] msgTimestamp = headers["svix-timestamp"] if !msgSignature || !msgId || !msgTimestamp msgId = headers["webhook-id"] msgSignature = headers["webhook-signature"] msgTimestamp = headers["webhook-timestamp"] if !msgSignature || !msgId || !msgTimestamp raise WebhookVerificationError, "Missing required headers" end end (msgTimestamp) _, signature = sign(msgId, msgTimestamp, payload).split(",", 2) passedSignatures = msgSignature.split(" ") passedSignatures.each do |versionedSignature| version, expectedSignature = versionedSignature.split(",", 2) if version != "v1" next end if ::Reattract::secure_compare(signature, expectedSignature) return JSON.parse(payload, symbolize_names: true) end end raise WebhookVerificationError, "No matching signature found" end |