openreceive-rails 0.3.0 → 0.3.2
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e7ef5df95a3cc1af66502a65a1b130aad1a88ab8ff93dcd26b4e93a1d732dca2
|
|
4
|
+
data.tar.gz: 291e45e4efa083eee2345490086e97e757ae3009aa0f79ba3a7ef3ba55a04bb5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 36a33f19c0791f0e127c7cb4bc6b746aa377a124d5e1c9cef9c553826416f6fb51383029c0b8ba1b0ad11e33e4b069e3156bff2d751adbafe0718825c99a9105
|
|
7
|
+
data.tar.gz: 18e1177d9a7974614eb8db63fe27c5414b21a0758c7e2f4f02d4e955970403217ebf6bbf3c94e1d7d840219ba99cdaf944f4bc0e64ad395fc7318937fef5e85f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.2 - 2026-08-29
|
|
4
|
+
|
|
5
|
+
No changes to this gem in 0.3.2. The release is the overpaid-deposit refund
|
|
6
|
+
mapping in `openreceive-server` and the browser packages' `resumePaymentHash`
|
|
7
|
+
resume path; the engine, its generators and the doctor task are byte-identical
|
|
8
|
+
to 0.3.1 and ship to keep the one-version-for-everything rule.
|
|
9
|
+
|
|
10
|
+
The Rails demo at `examples/buttons/server/rails` gained a testkit mode and a
|
|
11
|
+
`/checkout/:reference` route in this release. Neither is part of this gem.
|
|
12
|
+
|
|
13
|
+
## 0.3.1 - 2026-08-28
|
|
14
|
+
|
|
15
|
+
### The generated allow-all `config.authorize` is no longer silent
|
|
16
|
+
|
|
17
|
+
`openreceive:install` writes a `config.authorize` that allows every request,
|
|
18
|
+
treating possession of the reference as the authorization. It is now the named
|
|
19
|
+
constant `OpenReceive::ALLOW_ALL_AUTHORIZE`, for the same reason
|
|
20
|
+
`LOGGING_ON_PAID` is a constant: the engine detects it at boot by identity and
|
|
21
|
+
warns that anyone holding an order id can mint invoices, poll status and request
|
|
22
|
+
refunds for it. Safe only while references are unguessable. The five-minute demo
|
|
23
|
+
still works; it just stops being quiet about what it is.
|
|
24
|
+
|
|
25
|
+
### `bin/rails openreceive:doctor`
|
|
26
|
+
|
|
27
|
+
Step 0 of the agent directions as one command. It reports credential PRESENCE
|
|
28
|
+
only — every line is `set` or `unset`, and no secret is printed, echoed or
|
|
29
|
+
partially shown, which is what makes it safe to run in a shared terminal or
|
|
30
|
+
paste into an issue. Alongside that: whether `OpenReceive.configure` ran, which
|
|
31
|
+
hooks are missing or still the generated placeholders, where the engine is
|
|
32
|
+
mounted, and a wallet preflight.
|
|
33
|
+
|
|
34
|
+
The wallet line is last and best-effort. It builds the service — the same eager
|
|
35
|
+
preflight production boot runs, so a missing `NWC_URI`, a dead relay or a
|
|
36
|
+
SPEND-CAPABLE connection all answer here rather than on a payer's first checkout
|
|
37
|
+
— and reports the failure sanitized rather than raising it, because a doctor
|
|
38
|
+
that dies at line six tells an operator less than one that finishes.
|
|
39
|
+
|
|
40
|
+
"Look for `NWC_URI` in this app's server environment" has a different answer on
|
|
41
|
+
every host shape, and in a containerised app grepping the repo finds the name in
|
|
42
|
+
a compose file and proves nothing about the value. This asks the process, which
|
|
43
|
+
is the only place that always knows.
|
|
44
|
+
|
|
3
45
|
## 0.3.0 - 2026-08-26
|
|
4
46
|
|
|
5
47
|
### `config.amount_for` may return a `:description` beside the price
|
|
@@ -21,8 +21,9 @@ OpenReceive.configure do |config|
|
|
|
21
21
|
# prove this caller owns it.
|
|
22
22
|
# Return true to allow the request, false for a 403.
|
|
23
23
|
#
|
|
24
|
-
# The default below
|
|
25
|
-
#
|
|
24
|
+
# The default below is a NAMED PLACEHOLDER, and the engine warns at boot for
|
|
25
|
+
# as long as it is still here. It allows every request, treating possession of
|
|
26
|
+
# the reference as the authorization (an unknown reference is still a 404,
|
|
26
27
|
# because amount_for returns nil for it). That is only safe while your
|
|
27
28
|
# references are unguessable (UUIDs, not sequential integers). If they are
|
|
28
29
|
# enumerable, or an order should only be visible to the customer who placed
|
|
@@ -32,7 +33,7 @@ OpenReceive.configure do |config|
|
|
|
32
33
|
# order = Order.find_by(id: context[:resource][:reference])
|
|
33
34
|
# order && order.user_id == context[:request].session[:user_id]
|
|
34
35
|
# end
|
|
35
|
-
config.authorize =
|
|
36
|
+
config.authorize = OpenReceive::ALLOW_ALL_AUTHORIZE
|
|
36
37
|
|
|
37
38
|
# The price for a reference — the string your checkout passes, typically
|
|
38
39
|
# your order id. Your application is the only price authority; payer input
|
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
require "openreceive/server"
|
|
4
4
|
|
|
5
5
|
module OpenReceive
|
|
6
|
+
# The generated initializer's placeholder `config.authorize`: it allows every
|
|
7
|
+
# request, treating possession of the reference as the authorization. Kept as
|
|
8
|
+
# a named constant for the same reason LOGGING_ON_PAID is — the engine detects
|
|
9
|
+
# it at boot and says out loud that anyone holding an order id can mint
|
|
10
|
+
# invoices, poll status and request refunds for it. The five-minute demo still
|
|
11
|
+
# works; it just stops being silent.
|
|
12
|
+
ALLOW_ALL_AUTHORIZE = ->(_context) { true }
|
|
13
|
+
|
|
6
14
|
class ConfigurationError < StandardError; end
|
|
7
15
|
|
|
8
16
|
# Passed to the quickstart `config.on_paid` inside the settlement transaction,
|
|
@@ -415,6 +423,24 @@ module OpenReceive
|
|
|
415
423
|
preflight_skip_reason.nil?
|
|
416
424
|
end
|
|
417
425
|
|
|
426
|
+
# One line for `bin/rails openreceive:doctor`: did the wallet check pass?
|
|
427
|
+
#
|
|
428
|
+
# It builds the service, which is the same eager preflight the engine runs
|
|
429
|
+
# at production boot — a missing NWC_URI, a dead relay, or a SPEND-CAPABLE
|
|
430
|
+
# connection all answer here rather than on a payer's first checkout. The
|
|
431
|
+
# failure is reported, never raised: an operator running a doctor wants
|
|
432
|
+
# every other line too, and a doctor that dies at line six tells them less
|
|
433
|
+
# than one that finishes. Sanitized for the same reason the reconcile logs
|
|
434
|
+
# are — a connect failure can quote the NWC URI, secret and all.
|
|
435
|
+
def doctor_wallet_report
|
|
436
|
+
return "skipped — OpenReceive.configure has not run" unless configured?
|
|
437
|
+
|
|
438
|
+
config.service
|
|
439
|
+
"ok — the wallet answered and is receive-only"
|
|
440
|
+
rescue StandardError => error
|
|
441
|
+
"FAILED — #{sanitize_failure_message(error)}"
|
|
442
|
+
end
|
|
443
|
+
|
|
418
444
|
# nil when the boot preflight should run; otherwise the short reason the
|
|
419
445
|
# engine logs, so an operator who expected a fail-closed boot and did not
|
|
420
446
|
# get one can see why in the same log line.
|
data/lib/openreceive/engine.rb
CHANGED
|
@@ -33,6 +33,14 @@ module OpenReceive
|
|
|
33
33
|
"config/initializers/openreceive.rb."
|
|
34
34
|
)
|
|
35
35
|
end
|
|
36
|
+
if OpenReceive.config.authorize.equal?(OpenReceive::ALLOW_ALL_AUTHORIZE)
|
|
37
|
+
::Rails.logger&.warn(
|
|
38
|
+
"[openreceive] config.authorize is still the generated allow-all placeholder — " \
|
|
39
|
+
"anyone holding an order id can mint invoices, poll status, and request refunds " \
|
|
40
|
+
"for it. Safe only while your references are unguessable. Replace it in " \
|
|
41
|
+
"config/initializers/openreceive.rb."
|
|
42
|
+
)
|
|
43
|
+
end
|
|
36
44
|
if ::Rails.env.production?
|
|
37
45
|
skipped = OpenReceive.preflight_skip_reason
|
|
38
46
|
if skipped.nil?
|
data/lib/tasks/openreceive.rake
CHANGED
|
@@ -1,6 +1,60 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
namespace :openreceive do
|
|
4
|
+
# Step 0 of the agent directions, as one command.
|
|
5
|
+
#
|
|
6
|
+
# "Look for NWC_URI in this app's server environment" is a SEARCH, and it has
|
|
7
|
+
# a different answer on every host shape: a .env file, Rails credentials, a
|
|
8
|
+
# deploy config, or — in a containerised app — a value that exists only in the
|
|
9
|
+
# running process, fetched by a launcher script, where grepping the repo finds
|
|
10
|
+
# the NAME in a compose file and proves nothing about the value. This asks the
|
|
11
|
+
# process, which is the only place that always knows.
|
|
12
|
+
#
|
|
13
|
+
# PRESENCE ONLY. No secret is ever printed, echoed, or partially shown; every
|
|
14
|
+
# line is "set" or "unset". That rule is what makes this safe to run in a
|
|
15
|
+
# shared terminal, paste into an issue, or hand to a coding agent.
|
|
16
|
+
desc "Report OpenReceive's install state: credentials (set/unset only), engine mount, hooks"
|
|
17
|
+
task doctor: :environment do
|
|
18
|
+
set = ->(name) { ENV[name].to_s.strip.empty? ? "unset" : "set" }
|
|
19
|
+
lines = [
|
|
20
|
+
"openreceive:doctor",
|
|
21
|
+
" NWC_URI: #{set.call('NWC_URI')}",
|
|
22
|
+
" LSC_URI_PRIMARY: #{set.call('LSC_URI_PRIMARY')}",
|
|
23
|
+
" LSC_URI_BACKUP: #{set.call('LSC_URI_BACKUP')}"
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
if OpenReceive.configured?
|
|
27
|
+
config = OpenReceive.config
|
|
28
|
+
hook = lambda do |value, placeholder, name|
|
|
29
|
+
return "MISSING — the engine refuses to serve checkouts without it" if value.nil?
|
|
30
|
+
return "the generated placeholder (#{name}) — replace it" if value.equal?(placeholder)
|
|
31
|
+
|
|
32
|
+
"set"
|
|
33
|
+
end
|
|
34
|
+
lines << " configure: run"
|
|
35
|
+
lines << " authorize: #{hook.call(config.authorize, OpenReceive::ALLOW_ALL_AUTHORIZE,
|
|
36
|
+
'allow-all')}"
|
|
37
|
+
lines << " amount_for: #{config.amount_for.nil? ? 'MISSING — the engine refuses to serve checkouts without it' : 'set'}"
|
|
38
|
+
lines << " on_paid: #{hook.call(config.on_paid, OpenReceive::LOGGING_ON_PAID,
|
|
39
|
+
'logging-only')}"
|
|
40
|
+
else
|
|
41
|
+
lines << " configure: NOT RUN — run `bin/rails generate openreceive:install`"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
mount = Rails.application.routes.routes.find do |route|
|
|
45
|
+
route.app.respond_to?(:app) && route.app.app == OpenReceive::Engine
|
|
46
|
+
end
|
|
47
|
+
lines << " engine mounted: #{mount.nil? ? 'no — add `mount OpenReceive::Engine` to config/routes.rb' : "at #{mount.path.spec}"}"
|
|
48
|
+
|
|
49
|
+
# The wallet check, last and best-effort: it is the only line that talks to
|
|
50
|
+
# a relay, and a doctor that raises tells an operator less than one that
|
|
51
|
+
# reports. The receive-only verdict is the whole point — a spend-capable
|
|
52
|
+
# connection is refused, not warned about.
|
|
53
|
+
lines << " wallet preflight: #{OpenReceive.doctor_wallet_report}"
|
|
54
|
+
|
|
55
|
+
puts lines.join("\n")
|
|
56
|
+
end
|
|
57
|
+
|
|
4
58
|
desc "Run one OpenReceive reconciliation pass over pending payment attempts"
|
|
5
59
|
task reconcile: :environment do
|
|
6
60
|
checks = OpenReceive.reconcile!
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openreceive-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- OpenReceive
|
|
@@ -15,28 +15,28 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.3.
|
|
18
|
+
version: 0.3.2
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.3.
|
|
25
|
+
version: 0.3.2
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: openreceive-server
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - '='
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.3.
|
|
32
|
+
version: 0.3.2
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - '='
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.3.
|
|
39
|
+
version: 0.3.2
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: rails
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|