70.1.17. pepsi-stage-auto-pay¶
pay GNU Taler delivery demands automatically
- Manual section:
1
70.1.17.1.1. Name¶
pepsi-stage-auto-pay - the automatic pay-to-send settlement stage of the Pepsi pipeline.
70.1.17.1.2. Synopsis¶
pepsi-stage-auto-pay [GLOBAL-OPTIONS] worker
70.1.17.1.3. Description¶
pepsi-stage-auto-pay is a stage program run by pepsi-dispatch(1) as a persistent worker reading message ids on standard input. It has two roles, chosen per message:
On the inbound path it is the sending counterpart to pepsi-stage-anti-spam(1): when mail this site relayed is held at the far end behind a pay-to-send gate, that gate e-mails the original sender a payment demand, and this stage detects such demands and settles them automatically, so the held message is released and delivered.
On the submission path it is a wallet self-service endpoint: a locally submitted (authenticated) message addressed to the wallet control address lets the sender operate their own GNU Taler wallet by e-mail — check a balance, top it up, accept a peer push payment, or initiate a peer pull request. This role is enabled only when RESPONSE_STAGE is configured (see Wallet self-service below).
The two roles share one binary and are auto-detected, so a single
PROGRAM = pepsi-stage-auto-pay may be placed on either pipeline (or both, as two
[stage-<name>] sections).
A demand is recognised by the Taler: header that pepsi-stage-anti-spam(1)
adds to its payment-request auto-reply, carrying one or more taler://pay/…
URIs. A message with no Taler: header is ordinary mail and is forwarded to
NEXT_STAGE untouched, so the stage is safe to place early on the inbound path.
Pepsi only pays for mail it provably originated. The same auto-reply echoes the
original message’s Pepsi-Origin: proof-of-origin header (see
pepsi-stage-anti-spam(1) and pepsi-stage-relay-to-internet(1)). This
stage verifies it the same way a returning bounce is verified — the HMAC must
check against our secret and the nonce must still be tracked in
pepsi.origin_nonce. A demand that carries no valid proof (including every
demand when [pepsi-origin] is not configured) is never paid: it is
forwarded to NEXT_STAGE unchanged.
For a verified demand, the stage processes each taler://pay/… URI in turn,
driving the wallet through the privileged pepsi-helper-auto-pay(1) helper:
quote its price (the helper’s
previewoperation reads the order’s contract terms without paying);book it against a cumulative budget for the original message, capped by MAX_TOTAL; and
if it fits under the budget, settle it (the helper’s
payoperation spends wallet coins).
The budget is keyed on the Pepsi-Origin nonce, which identifies the original
outbound message. A message fanned out to a mailing list draws several demands —
one per member whose site charges — that all carry the same nonce, so they
share one budget: the per-message ledger in pepsi.origin_nonce.amount is
advanced atomically as each demand is settled (the auto_pay_try_spend function),
and a demand that would push the running total past MAX_TOTAL is refused. The
cap is single-currency: a demand whose currency differs from MAX_TOTAL is
not paid. An individual account can raise or lower its own cap with
pepsi-stage-edit-settings(1) (the override applies to mail addressed to that
account — i.e. the original sender, who receives the demand).
When every demand on a message has been settled, the now-redundant bounce is discarded (the row is deleted). If any demand cannot be priced, would exceed the budget, or differs in currency, the message is instead forwarded to NEXT_STAGE, so it proceeds as an ordinary bounce and the original sender is informed of the delivery problem as usual. A demand that was booked under the budget but then fails to pay is rolled back — the reservation is refunded to the per-message ledger (so the failed, un-spent payment does not consume the budget) — and the message is likewise forwarded. In short: auto-pay tries to pay; if it cannot, it does nothing (logging the error) and lets the bounce through.
70.1.17.1.4. Wallet account¶
The wallet the helper pays from is chosen by WALLET_MODE:
- local-user
The helper drops to the bounce recipient’s own local login (the original sender) and uses that user’s default wallet. The recipient must resolve to a permitted local account (the same LOCAL_DOMAINS/TARGETS/RECIPIENT_DELIMITER test as pepsi-stage-relay-to-maildir(1)); a non-local recipient cannot be charged and the message is forwarded.
- shared (default)
The helper drops to a single dedicated account (WALLET_USER, default
pepsi-wallets) whose home holds the wallet database(s). WALLET_SCOPE selects whether each original sender gets its own wallet database (per-sender, the default) or everyone shares one (unified— e.g. a business where individual wallets make no sense).
All wallet interaction is performed by the setuid-root pepsi-helper-auto-pay(1)
helper; this stage spawns it and never touches a wallet directly. The stage binary
is therefore installed SGID pepsi-wallets so its unprivileged dispatcher
worker may exec the helper (see Installation).
70.1.17.1.5. Wallet self-service¶
When RESPONSE_STAGE is set, a locally-originated message (state.local_origin
true; the submission listener must authenticate and bind the envelope sender)
addressed to <CONTROL_LOCAL_PART>@<served-domain> (default local part
pepsi-wallet; the domain is one of [pepsi-ingress] ACCEPTED_DOMAINS) is a
wallet-control message, operating the sender’s own wallet (resolved by
WALLET_MODE/WALLET_SCOPE exactly as for the paying role, but keyed on the
sender). Any other message is forwarded to NEXT_STAGE untouched, so the stage is
safe to place anywhere on the submission path.
The command is taken from the message Subject: line — one verb plus its arguments:
balanceReport the wallet balance.
withdrawCURRENCY:VALUE EXCHANGE-URLSet up a manual top-up of the given amount against the GNU Taler exchange at the given base URL. The exchange is named in the request (not configured on the server) because a wallet is multi-currency and can withdraw from many exchanges. The reply carries the bank
payto://target and the wire-transfer subject to use; once the user’s bank transfer arrives, the funds appear in the wallet.pullCURRENCY:VALUE [subject]Initiate a peer pull payment. The reply carries a
taler://pay-pull/…URI to forward to whoever should pay.pushtaler://pay-push/…Accept an incoming peer push payment. The URI may be given in the Subject or in the message body.
The result is mailed back to the sender as a localised auto-reply (null sender,
Auto-Submitted: auto-replied), built from the operator-customisable
wallet.<lang>.body template and injected at RESPONSE_STAGE (where it is
DKIM-signed and relayed); the original control message is then deleted. A request
that cannot be understood is answered with usage instructions.
If the wallet hits a KYC (identity-verification) requirement, the reply instead carries the KYC link for the user to open — this happens only for the self-service role, never while paying inbound demands.
70.1.17.1.6. Configuration¶
Options live in the stage’s own [stage-<name>] section
(PROGRAM = pepsi-stage-auto-pay): the required MAX_TOTAL (a GNU Taler
amount CURRENCY:VALUE bounding total spend per original message), a required
NEXT_STAGE, and the wallet knobs WALLET_MODE, WALLET_USER,
WALLET_SCOPE, WALLET_CLI, WALLET_PAY_OPTIONS and HELPER. The wallet
self-service role adds RESPONSE_STAGE (its presence enables the role),
CONTROL_LOCAL_PART, RESPONSE_FROM and RESPONSE_SUBJECT (a withdraw
names its own exchange base URL in the Subject, so no exchange is configured).
They are documented in pepsi.conf(5). The
proof-of-origin secret is the shared [pepsi-origin] section (see
pepsi-stage-relay-to-internet(1)); without it the stage can verify no demand
and therefore pays none (it does not affect self-service).
70.1.17.1.7. Installation¶
Because the stage execs the setuid-root wallet helper, its binary is installed
standalone (not folded into the unified pepsi binary) and SGID
pepsi-wallets (mode 2755); the helper is installed setuid-root,
root:pepsi-wallets, mode 4750. make install (targets
install-auto-pay-stage / install-auto-pay-helper) and the Debian package
apply these bits. The pepsi-wallets account and group are created by the
package; create them by hand otherwise.
70.1.17.1.8. State¶
Inputs: the Taler: and Pepsi-Origin: headers of the message (the body
is also scanned for an embedded Pepsi-Origin). The per-message spend ledger is
pepsi.origin_nonce.amount, not the message state.
Outputs: the stage does not modify the message; it advances or deletes it. The state layout is described in pepsi.state(7).
Transitions: finish (delete) when all demands are settled, or for a wallet
self-service control message (after injecting the reply at RESPONSE_STAGE);
otherwise advance to NEXT_STAGE (not a demand, unverifiable, unpriceable,
over budget, or a settlement failure). The stage never pauses, bounces or rewrites a
message.
70.1.17.1.9. Commands¶
- worker
Run as a persistent pepsi-dispatch(1) worker, reading message ids on standard input.
70.1.17.1.10. Global Options¶
- -c FILE, –config FILE
Read the configuration from FILE instead of searching the default locations.
- -L LOGLEVEL, –log LOGLEVEL
Set the logging verbosity (default
info).- -v, –verbose
Show log messages from all sources.
- -h, –help; -V, –version
Print a usage summary / the version and exit.
70.1.17.1.11. Exit Status¶
- 0
The message was processed (paid and discarded, or forwarded).
- 1
An error occurred (message not found or not
running, misconfigured stage — e.g. a missing MAX_TOTAL or NEXT_STAGE — or a database error). The reason is written to the log.
70.1.17.1.12. Examples¶
A pipeline section that pays delivery demands for locally-originated mail, up to
five euro per original message, from a single shared pepsi-wallets wallet:
[stage-auto-pay]
PROGRAM = pepsi-stage-auto-pay
MAX_TOTAL = EUR:5
NEXT_STAGE = local-delivery
WALLET_MODE = shared
WALLET_SCOPE = unified
Or, paying from each original sender’s own local wallet:
[stage-auto-pay]
PROGRAM = pepsi-stage-auto-pay
MAX_TOTAL = EUR:5
NEXT_STAGE = local-delivery
WALLET_MODE = local-user
Letting one account spend more (mailed by that account to pepsi@, see pepsi-stage-edit-settings(1)):
[stage-auto-pay]
MAX_TOTAL = EUR:20
A wallet self-service section on the submission path (a message to
pepsi-wallet@example.com with a command in the Subject operates the sender’s
wallet):
[stage-wallet]
PROGRAM = pepsi-stage-auto-pay
MAX_TOTAL = EUR:0
NEXT_STAGE = dkim-sign
RESPONSE_STAGE = dkim-sign
CONTROL_LOCAL_PART = pepsi-wallet
70.1.17.1.13. See Also¶
pepsi-helper-auto-pay(1), pepsi-stage-anti-spam(1), pepsi-stage-relay-to-internet(1), pepsi-stage-edit-settings(1), pepsi-config(1), pepsi-dispatch(1), pepsi.conf(5), pepsi.state(7), pepsi-setup(1)
70.1.17.1.14. Bugs¶
Report bugs to the Pepsi issue tracker.