85.1.17. pepsi-stage-auto-pay¶
pay GNU Taler delivery demands automatically
- Section du manuel:
1
85.1.17.1.1. Nom¶
pepsi-stage-auto-pay - l’étape de règlement automatique du péage à l’envoi du pipeline Pepsi.
85.1.17.1.2. Synopsis¶
pepsi-stage-auto-pay [GLOBAL-OPTIONS] worker
85.1.17.1.3. Description¶
pepsi-stage-auto-pay est un programme d’étape exécuté par pepsi-dispatch(1) comme un worker persistant lisant les identifiants de message sur l’entrée standard. Il a deux rôles, choisis par message :
Sur le chemin entrant, c’est le pendant émetteur de pepsi-stage-anti-spam(1) : lorsqu’un courrier que ce site a relayé est retenu à l’extrémité distante derrière une barrière de péage à l’envoi, cette barrière envoie par e-mail à l’expéditeur d’origine une demande de paiement, et cette étape détecte de telles demandes et les règle automatiquement, de sorte que le message retenu est libéré et remis.
Sur le chemin de soumission, c’est un point de terminaison de libre-service de wallet : un message soumis localement (authentifié) adressé à l’adresse de contrôle du wallet permet à l’expéditeur d’opérer son propre wallet GNU Taler par e-mail — consulter un solde, le recharger, accepter un paiement push de pair, ou initier une demande pull de pair. Ce rôle n’est activé que lorsque RESPONSE_STAGE est configuré (voir Libre-service de wallet ci-dessous).
Les deux rôles partagent un binaire et sont auto-détectés, de sorte qu’un unique PROGRAM = pepsi-stage-auto-pay peut être placé sur l’un ou l’autre pipeline (ou les deux, comme deux sections [stage-<name>]).
Une demande est reconnue par l’en-tête Taler: que pepsi-stage-anti-spam(1) ajoute à sa réponse automatique de demande de paiement, portant une ou plusieurs URI taler://pay/…. Seules les URI taler://pay/ sont jamais réglées — tout autre schéma taler:// dans cet en-tête (une URI pay-pull ou withdraw, qui constituerait une surface de siphonnage du wallet) est ignoré — et une URI répétée dans le ou les en-têtes ne compte qu’une fois. Un message sans en-tête Taler: est du courrier ordinaire et est transféré vers NEXT_STAGE sans modification, de sorte que l’étape peut être placée sans risque tôt sur le chemin entrant.
Pepsi ne paie que pour le courrier dont il est prouvablement à l’origine. La même réponse automatique renvoie en écho l’en-tête de preuve d’origine Pepsi-Origin: du message d’origine (voir pepsi-stage-anti-spam(1) et pepsi-stage-relay-to-internet(1)). Cette étape le vérifie de la même manière qu’un rebond de retour est vérifié — le HMAC doit se vérifier contre notre secret et le nonce doit encore être suivi dans pepsi.origin_nonce. Une demande qui ne porte aucune preuve valide (y compris toute demande lorsque [pepsi-origin] n’est pas configuré) n’est jamais payée : elle est transférée vers NEXT_STAGE inchangée.
Avertissement
L’en-tête authentifie le déploiement, non le rebond individuel. Il est apposé sur le message qui est remis, de sorte que chaque destinataire de ce message en détient une copie valide, et la vérification est un contrôle HMAC plus un contrôle d”existence du nonce — le nonce n’est pas consommé, n’est pas limité à un seul usage, et n’est pas lié au message pour lequel il a été frappé. N’importe quel destinataire peut donc rejouer l’en-tête sur un message à lui pendant tout le reste de la fenêtre de validité du nonce (14 jours) et faire traiter par cette étape les demandes Taler: qu’il y attache comme des demandes portant sur du courrier dont nous sommes à l’origine. MAX_TOTAL est la seule borne sur ce que cela coûte, et elle est par nonce — réglez-la donc sur un montant que vous acceptez de perdre par message sortant, et non par pipeline.
La preuve nomme aussi le compte pour lequel le message d’origine a été envoyé, et ce compte est le seul dont le wallet peut régler la demande : le destinataire d’enveloppe de la demande doit être ce même compte, comparé sans tenir compte de la casse. C’est cette liaison qui fait dire quelque chose à la preuve sur qui paie. Seule, elle dit uniquement que ce déploiement a envoyé un message sous ce nonce — et chaque correspondant ayant jamais reçu du courrier relayé par Pepsi détient une copie valide et encore suivie d’un tel en-tête — de sorte qu’une demande portant le Pepsi-Origin de quelqu’un d’autre et adressée à un autre utilisateur local serait sinon réglée sur le wallet de cet utilisateur. Une demande dont le destinataire n’est pas le compte nommé est transférée vers NEXT_STAGE sans être payée. (Notez que cela signifie aussi qu’un message dont l’expéditeur d’enveloppe a été réécrit par SRS avant le relais — du courrier tiers redirigé — n’attire aucun paiement automatique : la preuve nomme l’adresse réécrite, pas le destinataire auquel le rebond revient.)
Pour une demande vérifiée, l’étape traite chaque URI taler://pay/… à tour de rôle, pilotant le wallet via le helper privilégié pepsi-helper-auto-pay(1) :
coter son prix (l’opération
previewdu helper lit les termes du contrat du bon de commande sans payer) ;le réserver contre un budget cumulatif pour le message d’origine, plafonné par MAX_TOTAL, et contre le budget du wallet payeur sur les dernières 24 heures, plafonné par MAX_TOTAL_PER_DAY (lorsqu’il est défini) ; et
s’il tient sous les deux, le régler (l’opération
paydu helper dépense des pièces du wallet).
Chaque invocation du helper est bornée (cinq minutes ; l’enfant est tué s’il dépasse) et un timeout compte comme un échec, de sorte que la demande reste impayée et que le rebond est transféré. Un paiement qui a expiré peut néanmoins avoir abouti, ce que rien ici ne permet de savoir ; il est journalisé comme une erreur qui le dit. Cette borne existe parce que le backend marchand qu’une demande nomme est choisi par celui qui a écrit l’en-tête Taler: : une commande de wallet non bornée laisserait la ligne en running avec son worker incapable de prendre un autre message, et PARALLELISM demandes de ce genre arrêteraient l’étape — y compris le rôle de libre-service de wallet, s’il partage la section.
Le budget est indexé sur le nonce Pepsi-Origin, qui identifie le message sortant d’origine. Un message éclaté vers une liste de diffusion attire plusieurs demandes — une par membre dont le site facture — qui portent toutes le même nonce, de sorte qu’elles partagent un seul budget : le registre par message dans pepsi.origin_nonce.amount est avancé atomiquement à mesure que chaque demande est réglée (la fonction auto_pay_try_spend), et une demande qui pousserait le total courant au-delà de MAX_TOTAL est refusée. Le plafond est à monnaie unique : une demande dont la monnaie diffère de MAX_TOTAL n’est pas payée. Un compte individuel peut relever ou abaisser son propre plafond avec pepsi-stage-edit-settings(1) (la redéfinition s’applique au courrier adressé à ce compte — c.-à-d. l’expéditeur d’origine, qui reçoit la demande).
Le budget quotidien. MAX_TOTAL_PER_DAY borne ce qu’un wallet dépense en demandes sur 24 heures quelconques, quel que soit le nombre de messages d’origine sur lesquels elles se répartissent. Il est mesuré par wallet parce que le wallet est la seule chose que l’étape connaît toujours : sous WALLET_MODE local-user, le propre wallet de chaque utilisateur ; sous shared avec WALLET_SCOPE per-sender, la base de wallet de chaque expéditeur ; sous unified, l’unique wallet que tous partagent, de sorte que la limite est alors celle de tout le déploiement. Il n’est délibérément pas par correspondant : listes de diffusion et alias font que l’étape ne sait jamais avec certitude qui émet la demande. Chaque réservation est enregistrée dans pepsi.auto_pay_spend par le même appel auto_pay_try_spend qui fait avancer le registre par message — les deux vérifications et les deux écritures en une seule instruction, sérialisée par wallet, de sorte que des demandes concurrentes pour des messages différents ne peuvent pas non plus franchir ensemble la limite — et une demande refusée par l’un des budgets ne réserve rien sur l’autre. La fenêtre est glissante, et non un jour calendaire (qui permettrait deux fois la limite de part et d’autre de minuit), et les lignes qui en sont sorties sont élaguées par la même fonction. La limite est mono-monnaie et doit être dans la monnaie de MAX_TOTAL. S’il n’est pas défini, seul le budget par message s’applique.
Ce que MAX_TOTAL borne et ne borne pas. L’en-tête Taler: — l’hôte marchand, l’identifiant du bon de commande, et donc le prix — est choisi entièrement par l’extrémité distante et n’est couvert par rien : le MAC Pepsi-Origin lie la version, notre nom d’hôte, le compte d’origine, le nonce et un horodatage, et ne prouve donc que ceci : ce déploiement a envoyé un message sous ce nonce pour ce compte. Il ne lie ni la demande, ni le marchand, ni un montant. Chaque correspondant obtient une preuve valide et vivante 14 jours simplement en lisant le courrier que vous lui avez envoyé, de sorte qu’un correspondant peut toujours présenter une demande dont il fixe lui-même le prix, jusqu’à MAX_TOTAL, et être payé. MAX_TOTAL est donc une borne par message d’origine, non par correspondant et non par période : l’exposition totale à un correspondant déterminé croît avec le nombre de messages que vous lui avez envoyés. Réglez-la sur une somme que vous acceptez de payer pour une seule remise, et réglez MAX_TOTAL_PER_DAY sur ce qu’un wallet peut perdre en un jour lorsque chaque correspondant détenant une preuve l’encaisse — c’est cela, la limite de dépense.
Lorsque chaque demande sur un message a été réglée, le rebond désormais redondant est abandonné (la ligne est supprimée). Si une demande ne peut être tarifée, dépasserait l’un ou l’autre budget, ou diffère en monnaie, le message est à la place transféré vers NEXT_STAGE, de sorte qu’il poursuit comme un rebond ordinaire et que l’expéditeur d’origine soit informé du problème de remise comme d’habitude. Une demande qui a été réservée sous le budget mais qui échoue ensuite à être payée est annulée — la réservation est remboursée au registre par message, et sa réservation supprimée du registre quotidien, par la fonction auto_pay_refund (de sorte que le paiement échoué et non dépensé ne consomme aucun des deux budgets) — et le message est de même transféré, l’erreur étant journalisée. Auto-pay essaie de payer ; s’il ne peut pas, il ne fait rien et laisse passer le rebond.
L’exception est un helper qui ne peut pas être démarré du tout (un binaire manquant, un bit setuid perdu) : c’est une défaillance de l’hôte, non de la demande, donc tant qu’aucune demande du message n’a été payée, le message est réessayé plutôt que laissé passer, et l’auto-paiement ne cesse pas de payer en silence. Dès qu’une demande a été payée, aucune erreur sur le même message n’est réessayée — un réessai coterait, réserverait et paierait une seconde fois les demandes réglées — le rebond est donc transféré et l’erreur journalisée.
85.1.17.1.4. Compte wallet¶
Le wallet depuis lequel le helper paie est choisi par WALLET_MODE :
- local-user
Le helper abandonne ses privilèges vers le propre login local du compte payeur — le compte que nomme le
Pepsi-Originvérifié, qui est aussi le destinataire d’enveloppe de la demande (l’expéditeur d’origine) — et utilise le wallet par défaut de cet utilisateur. Il doit se résoudre en un compte local permis (le même test LOCAL_DOMAINS/TARGETS/RECIPIENT_DELIMITER que pepsi-stage-relay-to-maildir(1)) ; un compte non local ne peut être facturé et le message est transféré. Dans ce mode, le helper refuse un uid inférieur auUID_MINde/etc/login.defs, et pepsi-setup(1) avertit d’un jeton TARGETS qui descend en dessous.- shared (par défaut)
Le helper abandonne ses privilèges vers un unique compte dédié (WALLET_USER, par défaut
pepsi-wallets) dont le répertoire personnel contient la ou les bases de données de wallet. WALLET_SCOPE sélectionne si chaque expéditeur d’origine obtient sa propre base de données de wallet (per-sender, la valeur par défaut) ou si tout le monde en partage une (unified— par exemple une entreprise où des wallets individuels n’ont pas de sens).
Toute interaction avec le wallet est effectuée par le helper pepsi-helper-auto-pay(1) setuid-root ; cette étape le lance et ne touche jamais directement à un wallet. Le binaire de l’étape est donc installé SGID pepsi-wallets afin que son worker de dispatcher non privilégié puisse exec le helper (voir Installation).
85.1.17.1.5. Libre-service de wallet¶
Lorsque RESPONSE_STAGE est réglé, un message d’origine locale (state.local_origin vrai ; le listener de soumission doit authentifier et lier l’expéditeur d’enveloppe) adressé à <CONTROL_LOCAL_PART>@<served-domain> (partie locale par défaut pepsi-wallet ; le domaine est l’un de [pepsi-ingress] ACCEPTED_DOMAINS) est un message de contrôle de wallet, qui opère le wallet propre à l’expéditeur (résolu par WALLET_MODE/WALLET_SCOPE exactement comme pour le rôle de paiement, mais indexé sur l’expéditeur). Tout autre message est transféré vers NEXT_STAGE sans modification, de sorte que l’étape peut être placée n’importe où sur le chemin de soumission.
La commande est prise dans la ligne Subject: du message — un verbe plus ses arguments (le verbe est insensible à la casse) :
balanceRapporter le solde du wallet.
withdrawCURRENCY:VALUE EXCHANGE-URL (s’écrit aussitopup/top-up)Mettre en place un rechargement manuel du montant donné auprès de l’exchange GNU Taler à l’URL de base donnée (qui doit être une URL
http://ouhttps://). L’exchange est nommé dans la requête (et non configuré sur le serveur) car un wallet est multi-monnaie et peut retirer depuis plusieurs exchanges. La réponse porte la cible bancairepayto://et le sujet de virement à utiliser ; une fois le virement bancaire de l’utilisateur arrivé, les fonds apparaissent dans le wallet.pullCURRENCY:VALUE [subject]Initier un paiement pull de pair ; le reste de la ligne Subject, s’il y en a un, devient le sujet du paiement. La réponse porte une URI
taler://pay-pull/…à transmettre à celui qui doit payer.pushtaler://pay-push/… (s’écrit aussiaccept)Accepter un paiement push de pair entrant. L’URI peut être donnée dans le Subject ou dans le corps du message.
helpRépondre avec le mode d’emploi — ce que font également un Subject vide, un verbe inconnu, ou un argument manquant ou malformé.
Lorsque l’expéditeur ne se résout à aucun wallet (WALLET_MODE = local-user et un expéditeur qui n’est pas un compte local autorisé), rien n’est exécuté et la réponse le dit.
Le résultat est renvoyé par e-mail à l’expéditeur sous forme d’une réponse automatique localisée (expéditeur nul, Auto-Submitted: auto-replied), construite depuis le modèle wallet.<lang>.body personnalisable par l’opérateur et injectée à RESPONSE_STAGE (où elle est signée en DKIM et relayée) ; le message de contrôle d’origine est ensuite supprimé. Une requête qui ne peut être comprise reçoit en réponse des instructions d’usage. Une requête qui a été comprise mais qui a échoué reçoit en réponse un message fixe « n’a pas pu être menée à bien » : le diagnostic propre au wallet ne va que dans le journal de l’opérateur, puisqu’il décrit un wallet (partagé par tout le monde sous WALLET_SCOPE = unified) plutôt que la requête.
Le modèle de réponse est rendu une fois avant l’exécution de la commande de wallet, de sorte qu’un modèle manquant est réessayé sans que le wallet ait été touché. Une fois la commande exécutée, elle n’est jamais réexécutée pour le même message : une réponse qui ne peut alors être rendue ou mise en file est journalisée comme une erreur et la requête supprimée.
Si le wallet rencontre une exigence KYC (vérification d’identité), la réponse porte à la place le lien KYC que l’utilisateur doit ouvrir — cela n’arrive que pour le rôle de libre-service, jamais pendant le paiement de demandes entrantes.
85.1.17.1.6. Configuration¶
Les options résident dans la propre section [stage-<name>] de l’étape (PROGRAM = pepsi-stage-auto-pay) : le MAX_TOTAL obligatoire (un montant GNU Taler CURRENCY:VALUE bornant la dépense totale par message d’origine), le MAX_TOTAL_PER_DAY facultatif (dans la même monnaie, bornant la dépense d’un wallet sur 24 heures quelconques), un NEXT_STAGE obligatoire, et les réglages de wallet WALLET_MODE, WALLET_USER, WALLET_SCOPE, WALLET_CLI, WALLET_PAY_OPTIONS et HELPER. Le rôle de libre-service de wallet ajoute RESPONSE_STAGE (sa présence active le rôle), CONTROL_LOCAL_PART, RESPONSE_FROM et RESPONSE_SUBJECT (un withdraw nomme sa propre URL de base d’exchange dans le Subject, aucun exchange n’est donc configuré). Elles sont documentées dans pepsi.conf(5). Le secret de preuve d’origine est la section partagée [pepsi-origin] (voir pepsi-stage-relay-to-internet(1)) ; sans elle, l’étape ne peut vérifier aucune demande et n’en paie donc aucune (cela n’affecte pas le libre-service).
85.1.17.1.7. Installation¶
Comme l’étape exec le helper de wallet setuid-root, son binaire est installé autonome (non plié dans le binaire pepsi unifié) et SGID pepsi-wallets (mode 2550, propriétaire pepsi:pepsi-wallets — exécutable par le propriétaire et non par tout le monde, car le bit setgid est la barrière sur le helper, et pepsi n’est délibérément pas membre du groupe, de sorte que le droit d’exécution doit venir des bits du propriétaire) ; le helper est installé setuid-root, root:pepsi-wallets, mode 4750. make install (cibles install-auto-pay-stage / install-auto-pay-helper) et le paquet Debian appliquent ces bits. Le compte et le groupe pepsi-wallets sont créés par le paquet ; créez-les à la main sinon.
Le bit setgid étant cette barrière, le programme énonce lui-même la même règle : lorsque le binaire porte effectivement ce bit, alors, à moins que l’utilisateur réel ne soit root ou le compte de service pepsi, il sort en erreur avant qu’aucune configuration ne soit lue et — comme les étapes de cryptographie setuid — il retire les variables d’environnement qui pilotent le chargement de la configuration (HOME, XDG_CONFIG_HOME, PG*, TALER_*, PEPSI_*) et fixe PATH à une valeur par défaut sûre. (Une compilation installée sans le bit setgid — un arbre de développement, make check — n’a rien gagné et saute les deux étapes.) Un mode de fichier est un fait de déploiement et ceci est un fait de programme ; ni l’un ni l’autre n’est censé tenir seul.
85.1.17.1.8. État¶
Entrées : les en-têtes Taler: et Pepsi-Origin: du message (le corps est aussi parcouru à la recherche d’un Pepsi-Origin intégré). Le registre de dépense par message est pepsi.origin_nonce.amount et le registre quotidien par wallet pepsi.auto_pay_spend, pas le state du message.
Sorties : l’étape ne modifie pas le message ; elle l’avance ou le supprime. La disposition de l’état est décrite dans pepsi.state(7).
Transitions : finish (supprimer) lorsque toutes les demandes sont réglées, ou pour un message de contrôle de libre-service de wallet (après avoir injecté la réponse à RESPONSE_STAGE) ; sinon advance vers NEXT_STAGE (pas une demande, invérifiable, non tarifable, hors budget, ou un échec de règlement). L’étape ne met jamais un message en pause, ne le fait jamais rebondir et ne le réécrit jamais.
85.1.17.1.9. Commandes¶
- worker
Exécuté comme un worker persistant de pepsi-dispatch(1), lisant les identifiants de message sur l’entrée standard.
85.1.17.1.10. Options globales¶
- -c FILE, –config FILE
Lit la configuration depuis FILE au lieu de parcourir les emplacements par défaut.
- -L LOGLEVEL, –log LOGLEVEL
Règle la verbosité de journalisation (par défaut
info).- -v, –verbose
Affiche les messages de journal de toutes les sources.
- -h, –help ; -V, –version
Affiche un résumé d’utilisation / la version et quitte.
85.1.17.1.11. Code de sortie¶
- 0
Le message a été traité (payé et abandonné, ou transféré).
- 1
Une erreur s’est produite (message introuvable ou non
running, ou un paramètre par adresse qui casse la section de l’étape). La raison est écrite dans le journal.Une défaillance de l’hôte (la base de données, un modèle ou un helper inutilisable) n’est pas signalée comme un échec : le message est mis en pause et réessayé, comme le décrit Erreurs d’étape dans pepsi-dispatch(1). Une section qui ne s’analyse pas fait refuser au worker de démarrer (statut 78) au lieu de faire échouer chaque message tour à tour. L’absence de MAX_TOTAL est une telle section.
85.1.17.1.12. Exemples¶
Une section de pipeline qui paie les demandes de remise pour le courrier d’origine locale, jusqu’à cinq euros par message d’origine et cinquante par jour au total, depuis un unique wallet pepsi-wallets partagé
[stage-auto-pay]
PROGRAM = pepsi-stage-auto-pay
MAX_TOTAL = EUR:5
MAX_TOTAL_PER_DAY = EUR:50
NEXT_STAGE = local-delivery
WALLET_MODE = shared
WALLET_SCOPE = unified
Ou, en payant depuis le propre wallet local de chaque expéditeur d’origine
[stage-auto-pay]
PROGRAM = pepsi-stage-auto-pay
MAX_TOTAL = EUR:5
NEXT_STAGE = local-delivery
WALLET_MODE = local-user
Permettre à un compte de dépenser plus (envoyé par e-mail par ce compte à pepsi@, voir pepsi-stage-edit-settings(1))
[stage-auto-pay]
MAX_TOTAL = EUR:20
Une section de libre-service de wallet sur le chemin de soumission (un message vers pepsi-wallet@example.com avec une commande dans le Subject opère le wallet de l’expéditeur)
[stage-wallet]
PROGRAM = pepsi-stage-auto-pay
MAX_TOTAL = EUR:0
NEXT_STAGE = dkim-sign
RESPONSE_STAGE = dkim-sign
CONTROL_LOCAL_PART = pepsi-wallet
85.1.17.1.13. Voir aussi¶
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)
85.1.17.1.14. Bogues¶
Signalez les bogues au gestionnaire de tickets de Pepsi.