philiprehberger-webhook_builder 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77dfa24235cec307d4f733300a7db1f14b48a2a8b8716b73e6a122560ba57048
4
- data.tar.gz: 042a9b95d34042da93b03a6c7392afd1dae6c4dd215f3f8d4b61509a6034c8ab
3
+ metadata.gz: 7754a65fd17d3f711872d837db0a95670d245eab1da96df4d42c723b8d7f9f3d
4
+ data.tar.gz: 8be04c1b22974980e572ca5073279d995f6e8f67d8853742de62297e5951a532
5
5
  SHA512:
6
- metadata.gz: 5c8964553aac4756455514f60447c31f02912ec08d8a9f819edf66c9d094b0d12bbb4baa50f1901079d9b289dd4c7142aeb214067280b4aafb0991bf29e4441a
7
- data.tar.gz: 7c2dd0623d832973494e4276468f7f1723e1d28dd8c6aadb286f4f109c14a530c40231c217861d4e6f3e0dd37f21dec6ea3ca3e040c14ef0d70f0e801172dc0b
6
+ metadata.gz: 5f756201c37028a4f44d5975200d24fb811d87ecbc13467b9a9f3e5c792333c26dc546177871b9bda42d4bef3da1093202aa5f82279622521bf5c443d4fe61f8
7
+ data.tar.gz: c09e9a31e51d343140eb0beaa1db83560bd7a35dca976f00332534a888ece0eb8263a9701a6b5bf14720388ad381245b44b089689700fa0298ff9a5b16130742
data/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.0] - 2026-04-18
11
+
12
+ ### Added
13
+ - `Client#verify_signature(body:, signature:)` — constant-time HMAC-SHA256 comparison for the receiving side; returns `false` (never raises) on length mismatch
14
+
15
+ ## [0.2.2] - 2026-04-15
16
+
17
+ ### Changed
18
+ - Update homepage URI to portfolio hyphenated path
19
+
10
20
  ## [0.2.1] - 2026-03-31
11
21
 
12
22
  ### Changed
data/README.md CHANGED
@@ -114,6 +114,26 @@ client.deliver(
114
114
  )
115
115
  ```
116
116
 
117
+ ### Verifying signatures
118
+
119
+ On the receiving side, use the same secret to verify the signature sent in the
120
+ `X-Webhook-Signature` header. The comparison is constant-time and will never
121
+ raise on malformed input.
122
+
123
+ ```ruby
124
+ require "philiprehberger/webhook_builder"
125
+
126
+ secret = "shared-signing-secret"
127
+ sender = Philiprehberger::WebhookBuilder.new(url: "https://example.com/webhooks", secret: secret)
128
+ receiver = Philiprehberger::WebhookBuilder.new(url: "https://example.com/webhooks", secret: secret)
129
+
130
+ body = '{"event":"order.created","payload":{"id":1}}'
131
+ signature = OpenSSL::HMAC.hexdigest("SHA256", secret, body)
132
+
133
+ receiver.verify_signature(body: body, signature: signature) # => true
134
+ receiver.verify_signature(body: body, signature: "tampered") # => false
135
+ ```
136
+
117
137
  ### Delivery Tracking
118
138
 
119
139
  ```ruby
@@ -143,6 +163,7 @@ delivery.error # => nil or error message
143
163
  | `.new(url:, secret:, timeout:, max_retries:, backoff:, concurrency:, default_headers:)` | Create a webhook client |
144
164
  | `#deliver(event:, payload:, headers:)` | Deliver a webhook event and return a Delivery |
145
165
  | `#deliver_batch(events)` | Deliver multiple events concurrently and return an array of Delivery results |
166
+ | `#verify_signature(body:, signature:)` | Constant-time HMAC-SHA256 verification of an incoming signature; returns `true`/`false` and never raises |
146
167
 
147
168
  ### `Delivery`
148
169
 
@@ -137,6 +137,22 @@ module Philiprehberger
137
137
  results
138
138
  end
139
139
 
140
+ # Verify an HMAC-SHA256 signature against a raw request body.
141
+ #
142
+ # Uses a constant-time comparison to resist timing attacks. Returns
143
+ # +false+ (never raises) when the provided signature has a different
144
+ # length than the expected hex digest.
145
+ #
146
+ # @param body [String] the raw request body
147
+ # @param signature [String] the hex-encoded signature to verify
148
+ # @return [Boolean] true when the signature matches, false otherwise
149
+ def verify_signature(body:, signature:)
150
+ expected = sign(body)
151
+ return false unless signature.is_a?(String) && signature.bytesize == expected.bytesize
152
+
153
+ OpenSSL.fixed_length_secure_compare(expected, signature)
154
+ end
155
+
140
156
  private
141
157
 
142
158
  # Sign the request body with HMAC-SHA256.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module WebhookBuilder
5
- VERSION = '0.2.1'
5
+ VERSION = '0.3.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philiprehberger-webhook_builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philip Rehberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-31 00:00:00.000000000 Z
11
+ date: 2026-04-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A webhook delivery client that signs payloads with HMAC-SHA256, retries
14
14
  failed deliveries with configurable backoff strategies, supports batch delivery,
@@ -28,11 +28,11 @@ files:
28
28
  - lib/philiprehberger/webhook_builder/client.rb
29
29
  - lib/philiprehberger/webhook_builder/delivery.rb
30
30
  - lib/philiprehberger/webhook_builder/version.rb
31
- homepage: https://github.com/philiprehberger/rb-webhook-builder
31
+ homepage: https://philiprehberger.com/open-source-packages/ruby/philiprehberger-webhook_builder
32
32
  licenses:
33
33
  - MIT
34
34
  metadata:
35
- homepage_uri: https://github.com/philiprehberger/rb-webhook-builder
35
+ homepage_uri: https://philiprehberger.com/open-source-packages/ruby/philiprehberger-webhook_builder
36
36
  source_code_uri: https://github.com/philiprehberger/rb-webhook-builder
37
37
  changelog_uri: https://github.com/philiprehberger/rb-webhook-builder/blob/main/CHANGELOG.md
38
38
  bug_tracker_uri: https://github.com/philiprehberger/rb-webhook-builder/issues