taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 65359049ef9c5f2d8af1223a0f81c21975d24a46
parent 347dc5850fe47351c023baa1537111e99e1abdfc
Author: Florian Dold <florian@dold.me>
Date:   Mon, 19 May 2025 19:06:40 +0200

wallet-cli: handle pay-push URIs

Issue: https://bugs.taler.net/n/9972

Diffstat:
Mpackages/taler-wallet-cli/src/index.ts | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 131 insertions(+), 0 deletions(-)

diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts @@ -30,6 +30,7 @@ import { CoreApiResponse, Duration, encodeCrock, + ExchangeTosStatus, getErrorDetailFromException, getRandomBytes, InitRequest, @@ -46,6 +47,7 @@ import { TalerUriAction, TransactionIdStr, TransactionMajorState, + TransactionMinorState, WalletNotification, } from "@gnu-taler/taler-util"; import { clk } from "@gnu-taler/taler-util/clk"; @@ -695,6 +697,131 @@ withdrawCli }); }); +async function cliHandleTos( + wallet: WalletContext, + exchangeBaseUrl: string, +): Promise<boolean> { + while (1) { + const exch = await wallet.client.call( + WalletApiOperation.GetExchangeEntryByUrl, + { + exchangeBaseUrl, + }, + ); + if (exch.tosStatus === ExchangeTosStatus.Proposed) { + const res = await readlinePrompt( + `Accept terms of service of exchange ${exchangeBaseUrl}? [y/N/info]: `, + ); + switch (res.toLowerCase()) { + case "": + case "n": { + return false; + } + case "y": { + await wallet.client.call(WalletApiOperation.SetExchangeTosAccepted, { + exchangeBaseUrl, + }); + return true; + } + case "info": { + const tosText = await wallet.client.call( + WalletApiOperation.GetExchangeTos, + { + exchangeBaseUrl, + }, + ); + console.log(tosText.content); + } + } + } + } + throw Error("not reached"); +} + +/** + * Handle the user action of scanning a taler://pay-push/ URI. + */ +async function cliPeerPushCredit( + wallet: WalletContext, + uri: string, +): Promise<void> { + const prepRes = await wallet.client.call( + WalletApiOperation.PreparePeerPushCredit, + { + talerUri: uri, + }, + ); + const txDet = await wallet.client.call( + WalletApiOperation.GetTransactionById, + { + transactionId: prepRes.transactionId, + includeContractTerms: true, + }, + ); + if (txDet.txState.major === TransactionMajorState.Done) { + console.log("Payment already done in transaction history."); + return; + } + if ( + txDet.txState.major === TransactionMajorState.Dialog && + txDet.txState.minor === TransactionMinorState.Proposed + ) { + while (true) { + const res = await readlinePrompt( + `Accept payment of ${prepRes.amountEffective}? [y/N/info/delete]: `, + ); + let done = false; + switch (res.toLowerCase()) { + case "y": { + const tosOk = await cliHandleTos(wallet, prepRes.exchangeBaseUrl); + if (!tosOk) { + console.log( + "ToS needs to be accepted before payment can be accepted", + ); + done = true; + break; + } + await wallet.client.call(WalletApiOperation.ConfirmPeerPushCredit, { + transactionId: prepRes.transactionId, + }); + console.log( + "peer-push-credit confirmed, waiting for transaction to be final...", + ); + await wallet.client.call( + WalletApiOperation.TestingWaitTransactionState, + { + transactionId: prepRes.transactionId, + txState: [ + { major: TransactionMajorState.Done }, + { major: TransactionMajorState.Failed, minor: "*" }, + { major: TransactionMajorState.Aborted, minor: "*" }, + ], + }, + ); + done = true; + break; + } + case "": + case "n": { + done = true; + break; + } + case "info": { + console.log(`${j2s(txDet)}`); + break; + } + default: { + console.log("not understood"); + break; + } + } + if (done) { + break; + } + } + } +} + walletCli .subcommand("handleUri", "handle-uri", { help: "Handle a taler:// URI.", @@ -728,6 +855,10 @@ walletCli talerRefundUri: uri, }); break; + case TalerUriAction.PayPush: { + await cliPeerPushCredit(wallet, uri); + break; + } case TalerUriAction.Withdraw: { const withdrawInfo = await wallet.client.call( WalletApiOperation.GetWithdrawalDetailsForUri,