taler-typescript-core

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

commit 8e57ab32d8bff66fdf7575abcdb1161832c54b2f
parent 42a21c376bca1cabeeb7047d6b1c52432d7212d5
Author: Florian Dold <dold@taler.net>
Date:   Fri, 31 Jul 2026 15:47:40 +0200

wallet: find a purchase whose merchant base URL differs only in instance case

A downloaded proposal is filed under the base URL from the contract terms, so
re-scanning a taler:// URI that spells the instance differently claimed the
order again instead of returning the existing transaction.

Diffstat:
Mpackages/taler-wallet-core/src/pay-merchant.ts | 18+++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/packages/taler-wallet-core/src/pay-merchant.ts b/packages/taler-wallet-core/src/pay-merchant.ts @@ -33,6 +33,7 @@ import { AmountString, assertUnreachable, BlindedDonationReceiptKeyPair, + canonicalizeMerchantInstanceUrl, checkDbInvariant, checkLogicInvariant, ChoiceSelectionDetail, @@ -1496,8 +1497,23 @@ async function createOrReusePurchase( }> { // Find existing proposals from the same merchant // with the same order ID. + // + // Once a proposal has been downloaded its merchantBaseUrl is the one from + // the contract terms, which always spells the instance in lower case. A + // taler:// URI may spell it differently -- the merchant accepts any casing + // -- so look the record up under the canonical spelling as well, or + // re-scanning such a URI would claim the order a second time instead of + // returning the transaction that already exists. + const canonicalBaseUrl = canonicalizeMerchantInstanceUrl(merchantBaseUrl); const oldProposals = await wex.runWalletDbTx(async (tx) => { - return tx.getPurchasesByUrlAndOrderId(merchantBaseUrl, orderId); + const found = await tx.getPurchasesByUrlAndOrderId( + merchantBaseUrl, + orderId, + ); + if (found.length > 0 || canonicalBaseUrl === merchantBaseUrl) { + return found; + } + return tx.getPurchasesByUrlAndOrderId(canonicalBaseUrl, orderId); }); if (oldProposals.length > 1) {