belt-pay 0.0.5 → 0.0.6
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/CHANGELOG.md +12 -0
- data/README.md +7 -0
- data/lib/belt/pay/cli.rb +42 -9
- data/lib/belt/pay/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: df0a213a964e2b9d6e20019719612a03ae5a38fdafaade9f75bdb8b853f2ca87
|
|
4
|
+
data.tar.gz: 0a539c50414142e25667909c2858a45a00056e9afeb6b5f3ed824d50d7b50e30
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a8ece6c8fc7785233a665207bb5d68a7f652e3097d1706dd18fcb614b0b049a14d71b06f161fcda0acbd706ce01617061465c92b332f34c7f1f77021d2dafdd2
|
|
7
|
+
data.tar.gz: 5fae3025eff2bbc50cac637a22621d1f4de3b259a487653f5a3aeb2b6fe062312b6c4f9740088caa42288cc17d8b327bebaf698bc51fa819dc63a6d3767a98f4
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.0.6 — 2026-11-02
|
|
4
|
+
|
|
5
|
+
- **`pay:setup` works with a restricted runtime key.** The stored key is what the app
|
|
6
|
+
runs with, so it should be a restricted key (`rk_`) holding only what checkout and the
|
|
7
|
+
portal need. Setup used to manage the webhook endpoint with that same key, so a
|
|
8
|
+
restricted key without Webhook Endpoints access failed with a Stripe permission error.
|
|
9
|
+
When Stripe refuses the stored key, setup now asks once for a key that can manage
|
|
10
|
+
endpoints (an `sk_` secret key, or a restricted key with Webhook Endpoints: Write),
|
|
11
|
+
uses it for the endpoint list/create/delete calls in that run only, and never stores
|
|
12
|
+
it. A key from the other Stripe mode is refused. Leaving the prompt blank, or a second
|
|
13
|
+
refusal, falls back to the Dashboard steps; the stored key is still saved either way.
|
|
14
|
+
|
|
3
15
|
## 0.0.5 — 2026-10-31
|
|
4
16
|
|
|
5
17
|
- **`create_checkout` no longer drops Checkout Session options.** The Stripe provider used
|
data/README.md
CHANGED
|
@@ -200,6 +200,13 @@ either prompt blank to preserve its existing value. Use `--webhook-url` /
|
|
|
200
200
|
`BELT_PAY_WEBHOOK_URL` or `--webhook-events` / `BELT_PAY_WEBHOOK_EVENTS` to override the
|
|
201
201
|
defaults. Test (`sk_test_`) and live (`sk_live_`) keys get separate endpoints and secrets.
|
|
202
202
|
|
|
203
|
+
Prefer a [restricted key](https://docs.stripe.com/keys#limit-access) (`rk_`) as the
|
|
204
|
+
stored key, scoped to what your app calls at runtime (typically Customers, Checkout
|
|
205
|
+
Sessions, Customer portal and Subscriptions). It doesn't need Webhook Endpoints access:
|
|
206
|
+
when Stripe refuses it for the endpoint step, setup asks once for a key that can manage
|
|
207
|
+
endpoints (your `sk_` secret key, or a restricted key with Webhook Endpoints: Write),
|
|
208
|
+
uses it for that step only, and doesn't store it.
|
|
209
|
+
|
|
203
210
|
You can also pass the environment with standard Rake task-argument syntax:
|
|
204
211
|
|
|
205
212
|
```bash
|
data/lib/belt/pay/cli.rb
CHANGED
|
@@ -14,6 +14,7 @@ module Belt
|
|
|
14
14
|
module Pay
|
|
15
15
|
class CLI
|
|
16
16
|
class Error < StandardError; end
|
|
17
|
+
class EndpointKeyUnavailable < StandardError; end
|
|
17
18
|
|
|
18
19
|
COMMANDS = %w[secrets:setup secrets:show secrets:edit].freeze
|
|
19
20
|
WEBHOOK_PATH = '/pay/webhooks'
|
|
@@ -127,7 +128,7 @@ module Belt
|
|
|
127
128
|
updated['stripe_webhook_secret'] = webhook_secret unless blank?(webhook_secret)
|
|
128
129
|
|
|
129
130
|
update_secret(response, original, updated)
|
|
130
|
-
delete_replaced_endpoints(
|
|
131
|
+
delete_replaced_endpoints(replaced)
|
|
131
132
|
end
|
|
132
133
|
|
|
133
134
|
# Returns [signing_secret, endpoints_to_delete]. Offers to create the Stripe
|
|
@@ -147,7 +148,8 @@ module Belt
|
|
|
147
148
|
create = !url.nil? && confirm("Create the #{mode}-mode webhook endpoint in Stripe now?", default: blank?(existing_secret))
|
|
148
149
|
return [manual_webhook_secret(url, mode: mode), []] unless create
|
|
149
150
|
|
|
150
|
-
|
|
151
|
+
@endpoint_key = api_key
|
|
152
|
+
existing = with_endpoint_key(mode) { |key| stripe_endpoints(key) }.select { |endpoint| endpoint.url == url }
|
|
151
153
|
if existing.any?
|
|
152
154
|
ids = existing.map(&:id).join(', ')
|
|
153
155
|
@out.puts "Stripe already has an endpoint for this URL (#{ids}). Stripe never re-sends a signing secret,"
|
|
@@ -158,12 +160,17 @@ module Belt
|
|
|
158
160
|
end
|
|
159
161
|
end
|
|
160
162
|
|
|
161
|
-
endpoint =
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
endpoint = with_endpoint_key(mode) do |key|
|
|
164
|
+
::Stripe::WebhookEndpoint.create(
|
|
165
|
+
{ url: url, enabled_events: webhook_events, description: "Belt Pay (#{@app_name} #{@environment})" },
|
|
166
|
+
{ api_key: key }
|
|
167
|
+
)
|
|
168
|
+
end
|
|
165
169
|
@out.puts "Created #{mode}-mode webhook endpoint #{endpoint.id} for #{webhook_events.size} events."
|
|
166
170
|
[endpoint.secret, existing.map(&:id)]
|
|
171
|
+
rescue EndpointKeyUnavailable => e
|
|
172
|
+
@out.puts e.message
|
|
173
|
+
[manual_webhook_secret(url, mode: mode), []]
|
|
167
174
|
end
|
|
168
175
|
|
|
169
176
|
def manual_webhook_secret(url, mode: nil)
|
|
@@ -183,13 +190,38 @@ module Belt
|
|
|
183
190
|
hidden_prompt('Stripe webhook signing secret [blank keeps existing]')
|
|
184
191
|
end
|
|
185
192
|
|
|
186
|
-
def delete_replaced_endpoints(
|
|
193
|
+
def delete_replaced_endpoints(ids)
|
|
187
194
|
ids.each do |id|
|
|
188
|
-
::Stripe::WebhookEndpoint.delete(id, {}, { api_key:
|
|
195
|
+
::Stripe::WebhookEndpoint.delete(id, {}, { api_key: @endpoint_key })
|
|
189
196
|
@out.puts "Deleted replaced webhook endpoint #{id}"
|
|
190
197
|
end
|
|
191
198
|
end
|
|
192
199
|
|
|
200
|
+
# The stored key is what the app runs with, so it is usually a restricted key
|
|
201
|
+
# (rk_) without Webhook Endpoints access. When Stripe refuses it, ask once for a
|
|
202
|
+
# key that can manage endpoints (an sk_ secret key, or a restricted key with
|
|
203
|
+
# Webhook Endpoints: Write), use it for the endpoint calls in this run only, and
|
|
204
|
+
# never store it.
|
|
205
|
+
def with_endpoint_key(mode)
|
|
206
|
+
yield @endpoint_key
|
|
207
|
+
rescue ::Stripe::PermissionError => e
|
|
208
|
+
raise EndpointKeyUnavailable, "Stripe refused that key too: #{e.message}" if @endpoint_key_borrowed
|
|
209
|
+
|
|
210
|
+
@out.puts 'The stored Stripe key cannot manage webhook endpoints (a restricted key usually cannot).'
|
|
211
|
+
@out.puts 'Setup can use a second key for this step only; it is not stored.'
|
|
212
|
+
key = hidden_prompt("Stripe #{mode} secret key, or restricted key with Webhook Endpoints write [not stored]")
|
|
213
|
+
raise EndpointKeyUnavailable, 'No key given.' if blank?(key)
|
|
214
|
+
|
|
215
|
+
key = key.strip
|
|
216
|
+
unless stripe_mode(key) == mode
|
|
217
|
+
raise EndpointKeyUnavailable, "That is a #{stripe_mode(key)}-mode key; the stored key is #{mode} mode."
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
@endpoint_key = key
|
|
221
|
+
@endpoint_key_borrowed = true
|
|
222
|
+
retry
|
|
223
|
+
end
|
|
224
|
+
|
|
193
225
|
def stripe_endpoints(api_key)
|
|
194
226
|
::Stripe::WebhookEndpoint.list({ limit: 100 }, { api_key: api_key }).auto_paging_each.to_a
|
|
195
227
|
end
|
|
@@ -419,7 +451,8 @@ module Belt
|
|
|
419
451
|
|
|
420
452
|
Security:
|
|
421
453
|
secrets:setup reads values without echo and sends them directly through the
|
|
422
|
-
AWS SDK.
|
|
454
|
+
AWS SDK. If the stored key is a restricted key without Webhook Endpoints
|
|
455
|
+
access, it asks for a second key for the endpoint step and never stores it. secrets:show writes the complete secret to stdout. secrets:edit uses
|
|
423
456
|
a mode-0600 temporary file, validates JSON, and removes the file afterward.
|
|
424
457
|
HELP
|
|
425
458
|
end
|
data/lib/belt/pay/version.rb
CHANGED