patchwork-rb 0.1.6 → 0.1.7
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 +4 -4
- data/README.md +13 -1
- data/lib/patchwork/gateway.rb +5 -2
- data/lib/patchwork/signature.rb +13 -4
- data/lib/patchwork/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 966c3f0f6ac7395698a0f34d355813f86af4f8e685623197c0018b9c70ad53f7
|
|
4
|
+
data.tar.gz: 7919e2bd0ea6b8be6868f8bdc8972baaa727b9722d6be784458df7b702af1c96
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b84168c956d15378261d722a48d3de3a32df59b6176d10b3ed5d6789db6bbaf024b8bafbc89579edf2a497c5e1fbf238c7d9d894eebd22dffcbece6d500e9aa3
|
|
7
|
+
data.tar.gz: 5507f4f8baaa7c454669a3ce71b611313d78d58ba369b28969bfeada6488332122b38606e32672e12db0c0ec98baa96d12af1ca6daa728d1db8e7b55f238ee1d
|
data/README.md
CHANGED
|
@@ -238,7 +238,19 @@ A signature carries a label. `v1` covers the method, the path and the raw body.
|
|
|
238
238
|
|
|
239
239
|
The gateway and the concern verify either label, and pass the query for you. If you verify with the primitives instead, pass `query:` — the raw query string, `request.query_string` in Rack and Rails. Leave it out and a `v2` value is checked against the bare path, which will not match.
|
|
240
240
|
|
|
241
|
-
**
|
|
241
|
+
**By default a GET tool's arguments are not protected yet.** Patchwork sends both labels while consumers upgrade, and `v1` does not cover the query, so a header carrying both verifies through `v1` even if the query changed.
|
|
242
|
+
|
|
243
|
+
Two ways to close that:
|
|
244
|
+
|
|
245
|
+
```ruby
|
|
246
|
+
use Patchwork::Gateway,
|
|
247
|
+
resolve: ...,
|
|
248
|
+
labels: [ Patchwork::Signature::V2 ]
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Requiring `v2` refuses any signature that does not cover the query. Patchwork sends `v2` on every tool call, the relay mint, the connection probe and webhook deliveries, so this is safe to turn on today. It will fail against a platform that has not started sending `v2`, which is why it is not the default.
|
|
252
|
+
|
|
253
|
+
Or give any tool whose arguments matter — ids, amounts, anything that writes — a `POST` binding, where the arguments travel in the signed body.
|
|
242
254
|
|
|
243
255
|
The signed path is the one your app sees. If a proxy rewrites paths before your app does, mount the gateway where the original path is still intact.
|
|
244
256
|
|
data/lib/patchwork/gateway.rb
CHANGED
|
@@ -33,7 +33,7 @@ module Patchwork
|
|
|
33
33
|
|
|
34
34
|
def initialize(app, resolve:, subject: nil, mint_path: nil, health_check: true,
|
|
35
35
|
health_path: HealthCheck::PATH, max_body_bytes: MAX_BODY_BYTES,
|
|
36
|
-
replay_guard: nil)
|
|
36
|
+
replay_guard: nil, labels: Signature::LABELS)
|
|
37
37
|
raise ArgumentError, "resolve must respond to #call" unless resolve.respond_to?(:call)
|
|
38
38
|
raise ArgumentError, "subject must respond to #decode" if subject && !subject.respond_to?(:decode)
|
|
39
39
|
raise ArgumentError, "replay_guard must respond to #call" if replay_guard && !replay_guard.respond_to?(:call)
|
|
@@ -48,6 +48,8 @@ module Patchwork
|
|
|
48
48
|
@health_path = health_path.to_s
|
|
49
49
|
@max_body_bytes = Integer(max_body_bytes)
|
|
50
50
|
@replay_guard = replay_guard
|
|
51
|
+
@labels = Array(labels).map(&:to_s)
|
|
52
|
+
raise ArgumentError, "labels must name a signature version" if (@labels & Signature::LABELS).empty?
|
|
51
53
|
end
|
|
52
54
|
|
|
53
55
|
def call(env)
|
|
@@ -132,7 +134,8 @@ module Patchwork
|
|
|
132
134
|
method: method,
|
|
133
135
|
path: request.path,
|
|
134
136
|
query: request.query_string,
|
|
135
|
-
body: body
|
|
137
|
+
body: body,
|
|
138
|
+
labels: @labels
|
|
136
139
|
)
|
|
137
140
|
body
|
|
138
141
|
end
|
data/lib/patchwork/signature.rb
CHANGED
|
@@ -69,8 +69,16 @@ module Patchwork
|
|
|
69
69
|
# Accepts either label. During the migration Patchwork sends both, so a
|
|
70
70
|
# reader that understands v2 must still accept v1 from a platform that has
|
|
71
71
|
# not started sending it.
|
|
72
|
-
|
|
72
|
+
# `labels:` narrows what counts. The default accepts either, which is what
|
|
73
|
+
# the migration needs. Pass [V2] to refuse a signature that does not cover
|
|
74
|
+
# the query — stronger, but it fails against a platform still sending v1
|
|
75
|
+
# alone.
|
|
76
|
+
def self.verify(secrets:, header:, method:, path:, body:, query: nil, labels: LABELS,
|
|
77
|
+
skew: SKEW, now: Time.now.to_i)
|
|
73
78
|
secrets = usable!(secrets)
|
|
79
|
+
accepted = Array(labels).map(&:to_s) & LABELS
|
|
80
|
+
raise ArgumentError, "no known label to verify against" if accepted.empty?
|
|
81
|
+
|
|
74
82
|
parsed = parse(header)
|
|
75
83
|
return :bad if parsed.nil?
|
|
76
84
|
return :stale unless fresh?(parsed, skew: skew, now: now)
|
|
@@ -78,7 +86,7 @@ module Patchwork
|
|
|
78
86
|
# The body is hashed once however many candidates the header carries.
|
|
79
87
|
body_digest = digest(body)
|
|
80
88
|
|
|
81
|
-
matched =
|
|
89
|
+
matched = accepted.any? do |label|
|
|
82
90
|
candidates = parsed.signatures.fetch(label, []).select { |value| HEX_SHA256.match?(value) }
|
|
83
91
|
next false if candidates.empty?
|
|
84
92
|
|
|
@@ -90,9 +98,10 @@ module Patchwork
|
|
|
90
98
|
matched ? :ok : :bad
|
|
91
99
|
end
|
|
92
100
|
|
|
93
|
-
def self.verify!(secrets:, header:, method:, path:, body:, query: nil,
|
|
101
|
+
def self.verify!(secrets:, header:, method:, path:, body:, query: nil, labels: LABELS,
|
|
102
|
+
skew: SKEW, now: Time.now.to_i)
|
|
94
103
|
case verify(secrets: secrets, header: header, method: method, path: path, body: body,
|
|
95
|
-
query: query, skew: skew, now: now)
|
|
104
|
+
query: query, labels: labels, skew: skew, now: now)
|
|
96
105
|
when :stale then raise StaleSignature, "signature timestamp outside the #{skew}s window"
|
|
97
106
|
when :bad then raise InvalidSignature, "signature did not match"
|
|
98
107
|
else true
|
data/lib/patchwork/version.rb
CHANGED