From f6c01085113dfb004ca4478f276cfef0d2c24138 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 6 Sep 2019 11:06:28 +0200 Subject: fix bug #5373: only allow existing payment redirection for contracts from the same merchant --- src/wallet.ts | 39 ++++++++++++++++++++++++++++++--------- src/walletTypes.ts | 2 +- src/webex/pages/pay.tsx | 6 +++++- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/wallet.ts b/src/wallet.ts index ca829e3fa..bbdcf9224 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -733,10 +733,9 @@ export class Wallet { return fu.href(); } - /** * Check if a payment for the given taler://pay/ URI is possible. - * + * * If the payment is possible, the signature are already generated but not * yet send to the merchant. */ @@ -769,6 +768,31 @@ export class Wallet { console.log("proposal", proposal); + const differentPurchase = await this.q().getIndexed( + Stores.purchases.fulfillmentUrlIndex, + proposal.contractTerms.fulfillment_url, + ); + + if (differentPurchase) { + // We do this check to prevent merchant B to find out if we bought a + // digital product with merchant A by abusing the existing payment + // redirect feature. + if ( + differentPurchase.contractTerms.merchant_pub != + proposal.contractTerms.merchant_pub + ) { + console.warn( + "merchant with different public key offered contract with same fulfillment URL as an existing purchase", + ); + } else { + return { + status: "paid", + contractTerms: differentPurchase.contractTerms, + nextUrl: this.getNextUrl(differentPurchase.contractTerms), + }; + } + } + // First check if we already payed for it. const purchase = await this.q().get( Stores.purchases, @@ -779,7 +803,9 @@ export class Wallet { const paymentAmount = Amounts.parseOrThrow(proposal.contractTerms.amount); let wireFeeLimit; if (proposal.contractTerms.max_wire_fee) { - wireFeeLimit = Amounts.parseOrThrow(proposal.contractTerms.max_wire_fee); + wireFeeLimit = Amounts.parseOrThrow( + proposal.contractTerms.max_wire_fee, + ); } else { wireFeeLimit = Amounts.getZero(paymentAmount.currency); } @@ -835,16 +861,12 @@ export class Wallet { } if (uriResult.sessionId) { - await this.submitPay( - purchase.contractTermsHash, - uriResult.sessionId, - ); + await this.submitPay(purchase.contractTermsHash, uriResult.sessionId); } return { status: "paid", contractTerms: proposal.contractTerms, - proposalId: proposal.id!, nextUrl: this.getNextUrl(purchase.contractTerms), }; } @@ -1126,7 +1148,6 @@ export class Wallet { return sp; } - private async sendReserveInfoToBank(reservePub: string) { const reserve = await this.q().get( Stores.reserves, diff --git a/src/walletTypes.ts b/src/walletTypes.ts index 82024bb41..d29e3812e 100644 --- a/src/walletTypes.ts +++ b/src/walletTypes.ts @@ -471,9 +471,9 @@ export interface PreparePayResultError { error: string; } + export interface PreparePayResultPaid { status: "paid"; - proposalId: number; contractTerms: ContractTerms; nextUrl: string; } diff --git a/src/webex/pages/pay.tsx b/src/webex/pages/pay.tsx index 9041f5d1c..579688db3 100644 --- a/src/webex/pages/pay.tsx +++ b/src/webex/pages/pay.tsx @@ -92,10 +92,14 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) { ); const doPayment = async () => { + if (payStatus.status !== "payment-possible") { + throw Error("invalid state"); + } + const proposalId = payStatus.proposalId; setNumTries(numTries + 1); try { setLoading(true); - const res = await wxApi.confirmPay(payStatus!.proposalId!, undefined); + const res = await wxApi.confirmPay(proposalId, undefined); document.location.href = res.nextUrl; } catch (e) { console.error(e); -- cgit v1.2.3