This commit is contained in:
parent
94a995d814
commit
aaa7a8ce99
10 changed files with 543 additions and 8 deletions
|
|
@ -602,6 +602,43 @@ export namespace Catcrafts::Server {
|
|||
// "sepa" is final, "card" can be reversed for months.
|
||||
std::string_view BunqMethodFor(std::string_view paymentType);
|
||||
|
||||
// ── the bunq callback (webhook) ───────────────────────────────────
|
||||
//
|
||||
// bunq pushes a notification when the account changes, which is the only
|
||||
// way this shop learns about money when the API key's IP allowlist forbids
|
||||
// the web host from asking. Shape:
|
||||
//
|
||||
// {"NotificationUrl":{"category":"MUTATION",
|
||||
// "object":{"Payment":{…the same Payment object…}}}}
|
||||
//
|
||||
// SECURITY, stated plainly because the design depends on understanding it:
|
||||
// **bunq does not sign these.** Verified against doc.bunq.com — no HMAC, no
|
||||
// server signature; certificate pinning authenticates US to bunq, not bunq
|
||||
// to us. So the body is an unauthenticated claim that money arrived, and
|
||||
// the only things standing between it and the ledger are transport-level:
|
||||
// a source-IP allowlist for bunq's published range (185.40.108.0/22, which
|
||||
// bunq warns may change), a secret path segment, and the fact that nothing
|
||||
// ships without a human. Treat a callback as evidence exactly as strong as
|
||||
// those controls, and keep a periodic --pull-credits as the backstop:
|
||||
// bunq retries roughly six times and then drops the notification forever,
|
||||
// so a backend that was down during a deploy loses that payment silently.
|
||||
std::optional<BankCredit> ParseBunqCallback(std::string_view json);
|
||||
|
||||
// Append one credit to the file the transfer rail reads, unless an entry
|
||||
// with the same id is already there. Returns false on a write failure or a
|
||||
// duplicate — the caller answers the webhook 200 either way, because a
|
||||
// duplicate is a SUCCESS from bunq's point of view and retrying it would
|
||||
// achieve nothing.
|
||||
bool AppendCreditTo(const std::filesystem::path& creditsPath,
|
||||
const BankCredit& credit);
|
||||
|
||||
// Enable the bunq callback endpoint. Both arguments are required and the
|
||||
// secret must be at least 24 characters, or the endpoint stays off — see
|
||||
// ParseBunqCallback for why the path IS the authentication here, and why
|
||||
// that is only acceptable alongside Caddy's source-IP allowlist.
|
||||
void ConfigureBunqCallback(std::filesystem::path creditsPath,
|
||||
std::string secretPath);
|
||||
|
||||
// One pull: read the account and append every credit not already in the
|
||||
// file to it, newest last. Returns the number appended, or nullopt if the
|
||||
// bank could not be reached. This is what `--pull-credits` runs, and it is
|
||||
|
|
|
|||
Loading…
Reference in a new issue