commit 6337ac7b784d6556ebeb2dad3021ce40732511b9
parent 2eec83e5dfe015d11a2bb6a939662a6e61e95b6f
Author: Florian Dold <dold@taler.net>
Date: Wed, 29 Jul 2026 11:47:06 +0200
harness: check that a non-canonical suggested exchange fails the withdrawal
Issue: https://bugs.taler.net/n/10001
Diffstat:
2 files changed, 98 insertions(+), 0 deletions(-)
diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-bad-suggested-exchange.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-bad-suggested-exchange.ts
@@ -0,0 +1,96 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Imports.
+ */
+import { TalerErrorCode, j2s } from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { createSimpleTestkudosEnvironmentV3 } from "../harness/environments.js";
+import { GlobalTestState } from "../harness/harness.js";
+
+/**
+ * The exchange of the simple test environment always listens here.
+ */
+const exchangeBaseUrl = "http://localhost:8081/";
+
+/**
+ * The same exchange, but not a canonical base URL. A base URL is only ever
+ * used by resolving a relative path against it, and resolving "keys" against
+ * this one yields "http://localhost:8081/keys" -- so a wallet that accepts it
+ * ends up talking to a base URL the bank never named.
+ */
+const nonCanonicalExchangeBaseUrl = "http://localhost:8081/taler-exchange";
+
+/**
+ * Check that a bank-integrated withdrawal fails when the bank suggests an
+ * exchange base URL that isn't canonical.
+ */
+export async function runWithdrawalBadSuggestedExchangeTest(
+ t: GlobalTestState,
+) {
+ const { walletClient, bankClient, exchange } =
+ await createSimpleTestkudosEnvironmentV3(t, undefined, {
+ additionalBankConfig: (bank) => {
+ bank.changeConfig((config) => {
+ // Both bank implementations get misconfigured, each under the
+ // option name it reads.
+ config.setString(
+ "bank",
+ "suggested_exchange",
+ nonCanonicalExchangeBaseUrl,
+ );
+ config.setString(
+ "libeufin-bank",
+ "suggested_withdrawal_exchange",
+ nonCanonicalExchangeBaseUrl,
+ );
+ });
+ },
+ });
+
+ // Keep the constants above honest: the suggestion has to differ from the
+ // real base URL in nothing but its canonical form.
+ t.assertDeepEqual(exchange.baseUrl, exchangeBaseUrl);
+
+ const user = await bankClient.createRandomBankUser();
+ bankClient.setAuth(user);
+
+ const withdrawal = await bankClient.createWithdrawalOperation(
+ user.username,
+ "TESTKUDOS:10",
+ );
+
+ t.logStep("Hand the withdrawal to the wallet");
+
+ const err = await t.assertThrowsTalerErrorAsync(async () => {
+ const res = await walletClient.call(
+ WalletApiOperation.GetWithdrawalDetailsForUri,
+ {
+ talerWithdrawUri: withdrawal.taler_withdraw_uri,
+ },
+ );
+ console.log(`unexpectedly got withdrawal details: ${j2s(res)}`);
+ });
+
+ console.log(`got error: ${j2s(err.errorDetail)}`);
+ t.assertDeepEqual(
+ err.errorDetail.code,
+ TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+ );
+}
+
+runWithdrawalBadSuggestedExchangeTest.suites = ["wallet"];
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -235,6 +235,7 @@ import { runWebMerchantLoginTest } from "./test-web-merchant-login.js";
import { runWireMetadataTest } from "./test-wire-metadata.js";
import { runWithdrawalAbortBankTest } from "./test-withdrawal-abort-bank.js";
import { runWithdrawalAmountTest } from "./test-withdrawal-amount.js";
+import { runWithdrawalBadSuggestedExchangeTest } from "./test-withdrawal-bad-suggested-exchange.js";
import { runWithdrawalBankIntegratedTest } from "./test-withdrawal-bank-integrated.js";
import { runWithdrawalCashacceptorTest } from "./test-withdrawal-cashacceptor.js";
import { runWithdrawalConflictTest } from "./test-withdrawal-conflict.js";
@@ -335,6 +336,7 @@ const allTests: TestMainFunction[] = [
runWalletDblessTest,
runWallettestingTest,
runWithdrawalAbortBankTest,
+ runWithdrawalBadSuggestedExchangeTest,
runWithdrawalBankIntegratedTest,
runWithdrawalFakebankTest,
runWithdrawalFeesTest,