aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/headless/bank.ts143
-rw-r--r--src/headless/helpers.ts50
-rw-r--r--src/headless/integrationtest.ts327
-rw-r--r--src/headless/merchant.ts145
-rw-r--r--src/headless/taler-wallet-cli.ts286
-rw-r--r--src/index.ts1
-rw-r--r--src/util/http.ts22
-rw-r--r--src/wallet.ts10
-rw-r--r--src/walletCoreApiHandler.ts3
9 files changed, 36 insertions, 951 deletions
diff --git a/src/headless/bank.ts b/src/headless/bank.ts
deleted file mode 100644
index 2177908a6..000000000
--- a/src/headless/bank.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- 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/>
- */
-
-/**
- * Helper functions to deal with the GNU Taler demo bank.
- *
- * Mostly useful for automated tests.
- */
-
-/**
- * Imports.
- */
-import Axios from "axios";
-
-export interface BankUser {
- username: string;
- password: string;
-}
-
-/**
- * Generate a random alphanumeric ID. Does *not* use cryptographically
- * secure randomness.
- */
-function makeId(length: number): string {
- let result = "";
- const characters =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
- for (let i = 0; i < length; i++) {
- result += characters.charAt(Math.floor(Math.random() * characters.length));
- }
- return result;
-}
-
-/**
- * Helper function to generate the "Authorization" HTTP header.
- */
-function makeAuth(username: string, password: string): string {
- const auth = `${username}:${password}`;
- const authEncoded: string = Buffer.from(auth).toString("base64");
- return `Basic ${authEncoded}`;
-}
-
-/**
- * Client for the Taler bank access API.
- */
-export class Bank {
- constructor(private bankBaseUrl: string) {}
-
- async generateWithdrawUri(
- bankUser: BankUser,
- amount: string,
- ): Promise<string> {
- const body = {
- amount,
- };
-
- const reqUrl = new URL("api/withdraw-headless-uri", this.bankBaseUrl).href;
-
- const resp = await Axios({
- method: "post",
- url: reqUrl,
- data: body,
- responseType: "json",
- headers: {
- Authorization: makeAuth(bankUser.username, bankUser.password),
- },
- });
-
- if (resp.status != 200) {
- throw Error("failed to create bank reserve");
- }
-
- const withdrawUri = resp.data["taler_withdraw_uri"];
- if (!withdrawUri) {
- throw Error("Bank's response did not include withdraw URI");
- }
- return withdrawUri;
- }
-
- async createReserve(
- bankUser: BankUser,
- amount: string,
- reservePub: string,
- exchangePaytoUri: string,
- ): Promise<void> {
- const reqUrl = new URL("testing/withdraw", this.bankBaseUrl).href;
-
- const body = {
- username: bankUser,
- amount,
- reserve_pub: reservePub,
- exchange_payto_uri: exchangePaytoUri,
- };
-
- const resp = await Axios({
- method: "post",
- url: reqUrl,
- data: body,
- responseType: "json",
- headers: {
- Authorization: makeAuth(bankUser.username, bankUser.password),
- },
- });
-
- if (resp.status != 200) {
- throw Error("failed to create bank reserve");
- }
- }
-
- async registerRandomUser(): Promise<BankUser> {
- const reqUrl = new URL("testing/register", this.bankBaseUrl).href;
- const randId = makeId(8);
- const bankUser: BankUser = {
- username: `testuser-${randId}`,
- password: `testpw-${randId}`,
- };
-
- const resp = await Axios({
- method: "post",
- url: reqUrl,
- data: bankUser,
- responseType: "json",
- });
-
- if (resp.status != 200) {
- throw Error("could not register bank user");
- }
- return bankUser;
- }
-}
diff --git a/src/headless/helpers.ts b/src/headless/helpers.ts
index 3b2f65313..570ec9e69 100644
--- a/src/headless/helpers.ts
+++ b/src/headless/helpers.ts
@@ -26,18 +26,15 @@ import { Wallet } from "../wallet";
import { MemoryBackend, BridgeIDBFactory, shimIndexedDB } from "idb-bridge";
import { openTalerDatabase } from "../db";
import { HttpRequestLibrary } from "../util/http";
-import { Bank } from "./bank";
import fs from "fs";
import { NodeThreadCryptoWorkerFactory } from "../crypto/workers/nodeThreadWorker";
-import { WalletNotification, NotificationType } from "../types/notifications";
+import { WalletNotification } from "../types/notifications";
import { Database } from "../util/query";
import { NodeHttpLib } from "./NodeHttpLib";
import { Logger } from "../util/logging";
import { SynchronousCryptoWorkerFactory } from "../crypto/workers/synchronousWorker";
-import { WithdrawalSourceType } from "../types/dbTypes";
-import { Amounts } from "../util/amounts";
-const logger = new Logger("helpers.ts");
+const logger = new Logger("headless/helpers.ts");
export interface DefaultNodeWalletArgs {
/**
@@ -135,46 +132,3 @@ export async function getDefaultNodeWallet(
}
return w;
}
-
-export async function withdrawTestBalance(
- myWallet: Wallet,
- amount = "TESTKUDOS:10",
- bankBaseUrl = "https://bank.test.taler.net/",
- exchangeBaseUrl = "https://exchange.test.taler.net/",
-): Promise<void> {
- await myWallet.updateExchangeFromUrl(exchangeBaseUrl, true);
- const reserveResponse = await myWallet.acceptManualWithdrawal(
- exchangeBaseUrl,
- Amounts.parseOrThrow(amount),
- );
-
- const reservePub = reserveResponse.reservePub;
-
- const bank = new Bank(bankBaseUrl);
-
- const bankUser = await bank.registerRandomUser();
-
- logger.trace(`Registered bank user ${JSON.stringify(bankUser)}`);
-
- const exchangePaytoUri = await myWallet.getExchangePaytoUri(exchangeBaseUrl, [
- "x-taler-bank",
- ]);
-
- const donePromise = new Promise((resolve, reject) => {
- myWallet.runRetryLoop().catch((x) => {
- reject(x);
- });
- myWallet.addNotificationListener((n) => {
- if (
- n.type === NotificationType.WithdrawGroupFinished &&
- n.withdrawalSource.type === WithdrawalSourceType.Reserve &&
- n.withdrawalSource.reservePub === reservePub
- ) {
- resolve();
- }
- });
- });
-
- await bank.createReserve(bankUser, amount, reservePub, exchangePaytoUri);
- await donePromise;
-}
diff --git a/src/headless/integrationtest.ts b/src/headless/integrationtest.ts
deleted file mode 100644
index 8e1effbea..000000000
--- a/src/headless/integrationtest.ts
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- 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/>
- */
-
-/**
- * Integration tests against real Taler bank/exchange/merchant deployments.
- */
-
-import { getDefaultNodeWallet, withdrawTestBalance } from "./helpers";
-import { MerchantBackendConnection } from "./merchant";
-import { Logger } from "../util/logging";
-import { NodeHttpLib } from "./NodeHttpLib";
-import { Wallet } from "../wallet";
-import { Configuration } from "../util/talerconfig";
-import { Amounts, AmountJson } from "../util/amounts";
-
-const logger = new Logger("integrationtest.ts");
-
-export interface IntegrationTestArgs {
- exchangeBaseUrl: string;
- bankBaseUrl: string;
- merchantBaseUrl: string;
- merchantApiKey: string;
- amountToWithdraw: string;
- amountToSpend: string;
-}
-
-async function makePayment(
- wallet: Wallet,
- merchant: MerchantBackendConnection,
- amount: string,
- summary: string,
-): Promise<{ orderId: string }> {
- const orderResp = await merchant.createOrder(
- amount,
- summary,
- "taler://fulfillment-success/thx",
- );
-
- console.log("created order with orderId", orderResp.orderId);
-
- let paymentStatus = await merchant.checkPayment(orderResp.orderId);
-
- console.log("payment status", paymentStatus);
-
- const talerPayUri = paymentStatus.taler_pay_uri;
- if (!talerPayUri) {
- throw Error("no taler://pay/ URI in payment response");
- }
-
- const preparePayResult = await wallet.preparePayForUri(talerPayUri);
-
- console.log("prepare pay result", preparePayResult);
-
- if (preparePayResult.status != "payment-possible") {
- throw Error("payment not possible");
- }
-
- const confirmPayResult = await wallet.confirmPay(
- preparePayResult.proposalId,
- undefined,
- );
-
- console.log("confirmPayResult", confirmPayResult);
-
- paymentStatus = await merchant.checkPayment(orderResp.orderId);
-
- if (paymentStatus.order_status !== "paid") {
- console.log("payment status:", paymentStatus);
- throw Error("payment did not succeed");
- }
-
- return {
- orderId: orderResp.orderId,
- };
-}
-
-export async function runIntegrationTest(
- args: IntegrationTestArgs,
-): Promise<void> {
- logger.info("running test with arguments", args);
-
- const parsedSpendAmount = Amounts.parseOrThrow(args.amountToSpend);
- const currency = parsedSpendAmount.currency;
-
- const myHttpLib = new NodeHttpLib();
- myHttpLib.setThrottling(false);
-
- const myWallet = await getDefaultNodeWallet({ httpLib: myHttpLib });
-
- myWallet.runRetryLoop().catch((e) => {
- console.error("exception during retry loop:", e);
- });
-
- logger.info("withdrawing test balance");
- await withdrawTestBalance(
- myWallet,
- args.amountToWithdraw,
- args.bankBaseUrl,
- args.exchangeBaseUrl,
- );
- logger.info("done withdrawing test balance");
-
- const myMerchant = new MerchantBackendConnection(
- args.merchantBaseUrl,
- args.merchantApiKey,
- );
-
- await makePayment(myWallet, myMerchant, args.amountToSpend, "hello world");
-
- // Wait until the refresh is done
- await myWallet.runUntilDone();
-
- console.log("withdrawing test balance for refund");
- const withdrawAmountTwo: AmountJson = {
- currency,
- value: 18,
- fraction: 0,
- };
- const spendAmountTwo: AmountJson = {
- currency,
- value: 7,
- fraction: 0,
- };
-
- const refundAmount: AmountJson = {
- currency,
- value: 6,
- fraction: 0,
- };
-
- const spendAmountThree: AmountJson = {
- currency,
- value: 3,
- fraction: 0,
- };
- await withdrawTestBalance(
- myWallet,
- Amounts.stringify(withdrawAmountTwo),
- args.bankBaseUrl,
- args.exchangeBaseUrl,
- );
-
- // Wait until the withdraw is done
- await myWallet.runUntilDone();
-
- const { orderId: refundOrderId } = await makePayment(
- myWallet,
- myMerchant,
- Amounts.stringify(spendAmountTwo),
- "order that will be refunded",
- );
-
- const refundUri = await myMerchant.refund(
- refundOrderId,
- "test refund",
- Amounts.stringify(refundAmount),
- );
-
- console.log("refund URI", refundUri);
-
- await myWallet.applyRefund(refundUri);
-
- // Wait until the refund is done
- await myWallet.runUntilDone();
-
- await makePayment(
- myWallet,
- myMerchant,
- Amounts.stringify(spendAmountThree),
- "payment after refund",
- );
-
- await myWallet.runUntilDone();
-}
-
-export async function runIntegrationTestBasic(
- cfg: Configuration,
-): Promise<void> {
- const walletDbPath = cfg.getString("integrationtest", "walletdb").required();
-
- const bankBaseUrl = cfg
- .getString("integrationtest", "bank_base_url")
- .required();
-
- const exchangeBaseUrl = cfg
- .getString("integrationtest", "exchange_base_url")
- .required();
-
- const merchantBaseUrl = cfg
- .getString("integrationtest", "merchant_base_url")
- .required();
-
- const merchantApiKey = cfg
- .getString("integrationtest", "merchant_api_key")
- .required();
-
- const parsedWithdrawAmount = cfg
- .getAmount("integrationtest-basic", "amount_withdraw")
- .required();
-
- const parsedSpendAmount = cfg
- .getAmount("integrationtest-basic", "amount_spend")
- .required();
-
- const currency = parsedSpendAmount.currency;
-
- const myHttpLib = new NodeHttpLib();
- myHttpLib.setThrottling(false);
-
- const myWallet = await getDefaultNodeWallet({
- httpLib: myHttpLib,
- persistentStoragePath: walletDbPath,
- });
-
- myWallet.runRetryLoop().catch((e) => {
- console.error("exception during retry loop:", e);
- });
-
- logger.info("withdrawing test balance");
- await withdrawTestBalance(
- myWallet,
- Amounts.stringify(parsedWithdrawAmount),
- bankBaseUrl,
- exchangeBaseUrl,
- );
- logger.info("done withdrawing test balance");
-
- const balance = await myWallet.getBalances();
-
- console.log(JSON.stringify(balance, null, 2));
-
- const myMerchant = new MerchantBackendConnection(
- merchantBaseUrl,
- merchantApiKey,
- );
-
- await makePayment(
- myWallet,
- myMerchant,
- Amounts.stringify(parsedSpendAmount),
- "hello world",
- );
-
- // Wait until the refresh is done
- await myWallet.runUntilDone();
-
- console.log("withdrawing test balance for refund");
- const withdrawAmountTwo: AmountJson = {
- currency,
- value: 18,
- fraction: 0,
- };
- const spendAmountTwo: AmountJson = {
- currency,
- value: 7,
- fraction: 0,
- };
-
- const refundAmount: AmountJson = {
- currency,
- value: 6,
- fraction: 0,
- };
-
- const spendAmountThree: AmountJson = {
- currency,
- value: 3,
- fraction: 0,
- };
-
- await withdrawTestBalance(
- myWallet,
- Amounts.stringify(withdrawAmountTwo),
- bankBaseUrl,
- exchangeBaseUrl,
- );
-
- // Wait until the withdraw is done
- await myWallet.runUntilDone();
-
- const { orderId: refundOrderId } = await makePayment(
- myWallet,
- myMerchant,
- Amounts.stringify(spendAmountTwo),
- "order that will be refunded",
- );
-
- const refundUri = await myMerchant.refund(
- refundOrderId,
- "test refund",
- Amounts.stringify(refundAmount),
- );
-
- console.log("refund URI", refundUri);
-
- await myWallet.applyRefund(refundUri);
-
- // Wait until the refund is done
- await myWallet.runUntilDone();
-
- await makePayment(
- myWallet,
- myMerchant,
- Amounts.stringify(spendAmountThree),
- "payment after refund",
- );
-
- await myWallet.runUntilDone();
-
- console.log(
- "history after integration test:",
- JSON.stringify(history, undefined, 2),
- );
-}
diff --git a/src/headless/merchant.ts b/src/headless/merchant.ts
deleted file mode 100644
index 34ca5564d..000000000
--- a/src/headless/merchant.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- 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/>
- */
-
-/**
- * Helpers for talking to the GNU Taler merchant backend.
- * Used mostly for integration tests.
- */
-
-/**
- * Imports.
- */
-import axios from "axios";
-import {
- CheckPaymentResponse,
- codecForCheckPaymentResponse,
-} from "../types/talerTypes";
-
-/**
- * Connection to the *internal* merchant backend.
- */
-export class MerchantBackendConnection {
- async refund(
- orderId: string,
- reason: string,
- refundAmount: string,
- ): Promise<string> {
- const reqUrl = new URL(
- `private/orders/${orderId}/refund`,
- this.merchantBaseUrl,
- );
- const refundReq = {
- reason,
- refund: refundAmount,
- };
- const resp = await axios({
- method: "post",
- url: reqUrl.href,
- data: refundReq,
- responseType: "json",
- headers: {
- Authorization: `ApiKey ${this.apiKey}`,
- },
- });
- if (resp.status != 200) {
- throw Error("failed to do refund");
- }
- console.log("response", resp.data);
- const refundUri = resp.data.taler_refund_uri;
- if (!refundUri) {
- throw Error("no refund URI in response");
- }
- return refundUri;
- }
-
- constructor(public merchantBaseUrl: string, public apiKey: string) {}
-
- async authorizeTip(amount: string, justification: string): Promise<string> {
- const reqUrl = new URL("private/tips", this.merchantBaseUrl).href;
- const tipReq = {
- amount,
- justification,
- next_url: "about:blank",
- };
- const resp = await axios({
- method: "post",
- url: reqUrl,
- data: tipReq,
- responseType: "json",
- headers: {
- Authorization: `ApiKey ${this.apiKey}`,
- },
- });
- const tipUri = resp.data.taler_tip_uri;
- if (!tipUri) {
- throw Error("response does not contain tip URI");
- }
- return tipUri;
- }
-
- async createOrder(
- amount: string,
- summary: string,
- fulfillmentUrl: string,
- ): Promise<{ orderId: string }> {
- const t = Math.floor(new Date().getTime() / 1000) + 15 * 60;
- const reqUrl = new URL("private/orders", this.merchantBaseUrl).href;
- const orderReq = {
- order: {
- amount,
- summary,
- fulfillment_url: fulfillmentUrl,
- refund_deadline: { t_ms: t * 1000 },
- wire_transfer_deadline: { t_ms: t * 1000 },
- },
- };
- const resp = await axios({
- method: "post",
- url: reqUrl,
- data: orderReq,
- responseType: "json",
- headers: {
- Authorization: `ApiKey ${this.apiKey}`,
- },
- });
- if (resp.status != 200) {
- throw Error("failed to create bank reserve");
- }
- const orderId = resp.data.order_id;
- if (!orderId) {
- throw Error("no order id in response");
- }
- return { orderId };
- }
-
- async checkPayment(orderId: string): Promise<CheckPaymentResponse> {
- const reqUrl = new URL(`private/orders/${orderId}`, this.merchantBaseUrl)
- .href;
- const resp = await axios({
- method: "get",
- url: reqUrl,
- responseType: "json",
- headers: {
- Authorization: `ApiKey ${this.apiKey}`,
- },
- });
- if (resp.status != 200) {
- throw Error("failed to check payment");
- }
-
- return codecForCheckPaymentResponse().decode(resp.data);
- }
-}
diff --git a/src/headless/taler-wallet-cli.ts b/src/headless/taler-wallet-cli.ts
index ba629537e..a7f306ec3 100644
--- a/src/headless/taler-wallet-cli.ts
+++ b/src/headless/taler-wallet-cli.ts
@@ -16,9 +16,7 @@
import os from "os";
import fs from "fs";
-import { getDefaultNodeWallet, withdrawTestBalance } from "./helpers";
-import { MerchantBackendConnection } from "./merchant";
-import { runIntegrationTest, runIntegrationTestBasic } from "./integrationtest";
+import { getDefaultNodeWallet } from "./helpers";
import { Wallet } from "../wallet";
import qrcodeGenerator from "qrcode-generator";
import * as clk from "./clk";
@@ -34,7 +32,6 @@ import {
OperationFailedAndReportedError,
OperationFailedError,
} from "../operations/errors";
-import { Bank } from "./bank";
import { classifyTalerUri, TalerUriType } from "../util/taleruri";
import { Configuration } from "../util/talerconfig";
import { setDangerousTimetravel } from "../util/time";
@@ -658,285 +655,4 @@ testCli.subcommand("vectors", "vectors").action(async (args) => {
console.log(` (out) coin pub: ${encodeCrock(p.coinPub)}`);
});
-testCli
- .subcommand("integrationtestBasic", "integrationtest-basic")
- .requiredArgument("cfgfile", clk.STRING)
- .action(async (args) => {
- const cfgStr = fs.readFileSync(args.integrationtestBasic.cfgfile, "utf8");
- const cfg = new Configuration();
- cfg.loadFromString(cfgStr);
- try {
- await runIntegrationTestBasic(cfg);
- } catch (e) {
- console.log("integration test failed");
- console.log(e);
- process.exit(1);
- }
- process.exit(0);
- });
-
-testCli
- .subcommand("testPayCmd", "test-pay", { help: "Create contract and pay." })
- .requiredOption("merchant", ["-m", "--mechant-url"], clk.STRING)
- .requiredOption("apikey", ["-k", "--mechant-api-key"], clk.STRING)
- .requiredOption("amount", ["-a", "--amount"], clk.STRING)
- .requiredOption("summary", ["-s", "--summary"], clk.STRING, {
- default: "Test Payment",
- })
- .action(async (args) => {
- const cmdArgs = args.testPayCmd;
- console.log("creating order");
- const merchantBackend = new MerchantBackendConnection(
- args.testPayCmd.merchant,
- args.testPayCmd.apikey,
- );
- const orderResp = await merchantBackend.createOrder(
- cmdArgs.amount,
- cmdArgs.summary,
- "",
- );
- console.log("created new order with order ID", orderResp.orderId);
- const checkPayResp = await merchantBackend.checkPayment(orderResp.orderId);
- const talerPayUri = checkPayResp.taler_pay_uri;
- if (!talerPayUri) {
- console.error("fatal: no taler pay URI received from backend");
- process.exit(1);
- return;
- }
- console.log("taler pay URI:", talerPayUri);
- await withWallet(args, async (wallet) => {
- await doPay(wallet, talerPayUri, { alwaysYes: true });
- });
- });
-
-testCli
- .subcommand("integrationtestCmd", "integrationtest", {
- help: "Run integration test with bank, exchange and merchant.",
- })
- .requiredOption("exchange", ["-e", "--exchange"], clk.STRING, {
- default: "https://exchange.test.taler.net/",
- })
- .requiredOption("merchant", ["-m", "--merchant"], clk.STRING, {
- default: "https://backend.test.taler.net/",
- })
- .requiredOption("merchantApiKey", ["-k", "--merchant-api-key"], clk.STRING, {
- default: "sandbox",
- })
- .requiredOption("bank", ["-b", "--bank"], clk.STRING, {
- default: "https://bank.test.taler.net/",
- })
- .requiredOption("withdrawAmount", ["-w", "--amount"], clk.STRING, {
- default: "TESTKUDOS:10",
- })
- .requiredOption("spendAmount", ["-s", "--spend-amount"], clk.STRING, {
- default: "TESTKUDOS:4",
- })
- .action(async (args) => {
- applyVerbose(args.wallet.verbose);
- const cmdObj = args.integrationtestCmd;
-
- try {
- await runIntegrationTest({
- amountToSpend: cmdObj.spendAmount,
- amountToWithdraw: cmdObj.withdrawAmount,
- bankBaseUrl: cmdObj.bank,
- exchangeBaseUrl: cmdObj.exchange,
- merchantApiKey: cmdObj.merchantApiKey,
- merchantBaseUrl: cmdObj.merchant,
- }).catch((err) => {
- console.error("Integration test failed with exception:");
- console.error(err);
- process.exit(1);
- });
- process.exit(0);
- } catch (e) {
- console.error(e);
- process.exit(1);
- }
- });
-
-testCli
- .subcommand("genTipUri", "gen-tip-uri", {
- help: "Generate a taler://tip URI.",
- })
- .requiredOption("amount", ["-a", "--amount"], clk.STRING, {
- default: "TESTKUDOS:10",
- })
- .maybeOption("merchant", ["-m", "--merchant"], clk.STRING, {
- default: "https://backend.test.taler.net/",
- })
- .maybeOption("merchantApiKey", ["-k", "--merchant-api-key"], clk.STRING, {
- default: "sandbox",
- })
- .action(async (args) => {
- const merchantBackend = new MerchantBackendConnection(
- args.genTipUri.merchant ?? "https://backend.test.taler.net/",
- args.genTipUri.merchantApiKey ?? "sandbox",
- );
- const tipUri = await merchantBackend.authorizeTip(
- args.genTipUri.amount,
- "test",
- );
- console.log(tipUri);
- });
-
-testCli
- .subcommand("genWithdrawUri", "gen-withdraw-uri", {
- help: "Generate a taler://withdraw URI.",
- })
- .requiredOption("amount", ["-a", "--amount"], clk.STRING, {
- default: "TESTKUDOS:20",
- })
- .requiredOption("bank", ["-b", "--bank"], clk.STRING, {
- default: "https://bank.test.taler.net/",
- })
- .action(async (args) => {
- const b = new Bank(args.genWithdrawUri.bank);
- const user = await b.registerRandomUser();
- const url = await b.generateWithdrawUri(user, args.genWithdrawUri.amount);
- console.log(url);
- });
-
-testCli
- .subcommand("genRefundUri", "gen-refund-uri", {
- help: "Generate a taler://refund URI.",
- })
- .requiredOption("amount", ["-a", "--amount"], clk.STRING, {
- default: "TESTKUDOS:5",
- })
- .requiredOption("refundAmount", ["-r", "--refund"], clk.STRING, {
- default: "TESTKUDOS:3",
- })
- .requiredOption("summary", ["-s", "--summary"], clk.STRING, {
- default: "Test Payment (for refund)",
- })
- .maybeOption("merchant", ["-m", "--merchant"], clk.STRING, {
- default: "https://backend.test.taler.net/",
- })
- .maybeOption("merchantApiKey", ["-k", "--merchant-api-key"], clk.STRING, {
- default: "sandbox",
- })
- .action(async (args) => {
- const cmdArgs = args.genRefundUri;
- const merchantBackend = new MerchantBackendConnection(
- cmdArgs.merchant ?? "https://backend.test.taler.net/",
- cmdArgs.merchantApiKey ?? "sandbox",
- );
- const orderResp = await merchantBackend.createOrder(
- cmdArgs.amount,
- cmdArgs.summary,
- "",
- );
- console.log("created new order with order ID", orderResp.orderId);
- const checkPayResp = await merchantBackend.checkPayment(orderResp.orderId);
- const talerPayUri = checkPayResp.taler_pay_uri;
- if (!talerPayUri) {
- console.error("fatal: no taler pay URI received from backend");
- process.exit(1);
- return;
- }
- await withWallet(args, async (wallet) => {
- await doPay(wallet, talerPayUri, { alwaysYes: true });
- });
- const refundUri = await merchantBackend.refund(
- orderResp.orderId,
- "test refund",
- cmdArgs.refundAmount,
- );
- console.log(refundUri);
- });
-
-testCli
- .subcommand("genPayUri", "gen-pay-uri", {
- help: "Generate a taler://pay URI.",
- })
- .flag("qrcode", ["--qr"], {
- help: "Show a QR code with the taler://pay URI",
- })
- .flag("wait", ["--wait"], {
- help: "Wait until payment has completed",
- })
- .requiredOption("amount", ["-a", "--amount"], clk.STRING, {
- default: "TESTKUDOS:1",
- })
- .requiredOption("summary", ["-s", "--summary"], clk.STRING, {
- default: "Test Payment",
- })
- .requiredOption("merchant", ["-m", "--merchant"], clk.STRING, {
- default: "https://backend.test.taler.net/",
- })
- .requiredOption("merchantApiKey", ["-k", "--merchant-api-key"], clk.STRING, {
- default: "sandbox",
- })
- .action(async (args) => {
- const cmdArgs = args.genPayUri;
- console.log("creating order");
- const merchantBackend = new MerchantBackendConnection(
- cmdArgs.merchant,
- cmdArgs.merchantApiKey,
- );
- const orderResp = await merchantBackend.createOrder(
- cmdArgs.amount,
- cmdArgs.summary,
- "",
- );
- console.log("created new order with order ID", orderResp.orderId);
- const checkPayResp = await merchantBackend.checkPayment(orderResp.orderId);
- const talerPayUri = checkPayResp.taler_pay_uri;
- if (!talerPayUri) {
- console.error("fatal: no taler pay URI received from backend");
- process.exit(1);
- return;
- }
- console.log("taler pay URI:", talerPayUri);
- if (cmdArgs.qrcode) {
- const qrcode = qrcodeGenerator(0, "M");
- qrcode.addData(talerPayUri);
- qrcode.make();
- console.log(qrcode.createASCII());
- }
- if (cmdArgs.wait) {
- console.log("waiting for payment ...");
- while (1) {
- await asyncSleep(500);
- const checkPayResp2 = await merchantBackend.checkPayment(
- orderResp.orderId,
- );
- if (checkPayResp2.order_status === "paid") {
- console.log("payment successfully received!");
- break;
- }
- }
- }
- });
-
-testCli
- .subcommand("withdrawArgs", "withdraw", {
- help: "Withdraw from a test bank (must support test registrations).",
- })
- .requiredOption("amount", ["-a", "--amount"], clk.STRING, {
- default: "TESTKUDOS:10",
- help: "Amount to withdraw.",
- })
- .requiredOption("exchange", ["-e", "--exchange"], clk.STRING, {
- default: "https://exchange.test.taler.net/",
- help: "Exchange base URL.",
- })
- .requiredOption("bank", ["-b", "--bank"], clk.STRING, {
- default: "https://bank.test.taler.net/",
- help: "Bank base URL",
- })
- .action(async (args) => {
- await withWallet(args, async (wallet) => {
- await wallet.updateExchangeFromUrl(args.withdrawArgs.exchange, true);
- await withdrawTestBalance(
- wallet,
- args.withdrawArgs.amount,
- args.withdrawArgs.bank,
- args.withdrawArgs.exchange,
- );
- logger.info("Withdraw done");
- });
- });
-
walletCli.run();
diff --git a/src/index.ts b/src/index.ts
index 3a5cd9497..147d7b1e0 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -19,5 +19,4 @@
*/
export { Wallet } from "./wallet";
-export { runIntegrationTest } from "./headless/integrationtest";
export { installAndroidWalletListener } from "./android";
diff --git a/src/util/http.ts b/src/util/http.ts
index abbc8df03..38892491b 100644
--- a/src/util/http.ts
+++ b/src/util/http.ts
@@ -300,6 +300,7 @@ export async function readSuccessResponseJsonOrThrow<T>(
throwUnexpectedRequestError(httpResponse, r.talerErrorResponse);
}
+
export async function readSuccessResponseTextOrErrorCode<T>(
httpResponse: HttpResponse,
): Promise<ResponseOrError<string>> {
@@ -329,6 +330,27 @@ export async function readSuccessResponseTextOrErrorCode<T>(
};
}
+export async function checkSuccessResponseOrThrow(
+ httpResponse: HttpResponse,
+): Promise<void> {
+ if (!(httpResponse.status >= 200 && httpResponse.status < 300)) {
+ const errJson = await httpResponse.json();
+ const talerErrorCode = errJson.code;
+ if (typeof talerErrorCode !== "number") {
+ throw new OperationFailedError(
+ makeErrorDetails(
+ TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+ "Error response did not contain error code",
+ {
+ requestUrl: httpResponse.requestUrl,
+ },
+ ),
+ );
+ }
+ throwUnexpectedRequestError(httpResponse, errJson);
+ }
+}
+
export async function readSuccessResponseTextOrThrow<T>(
httpResponse: HttpResponse,
): Promise<string> {
diff --git a/src/wallet.ts b/src/wallet.ts
index 758336c58..4d22bd591 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -113,6 +113,7 @@ import {
TransactionsResponse,
} from "./types/transactions";
import { getTransactions } from "./operations/transactions";
+import { withdrawTestBalance } from "./operations/testing";
const builtinCurrencies: CurrencyRecord[] = [
{
@@ -868,4 +869,13 @@ export class Wallet {
): Promise<TransactionsResponse> {
return getTransactions(this.ws, request);
}
+
+
+ async withdrawTestBalance(
+ amount = "TESTKUDOS:10",
+ bankBaseUrl = "https://bank.test.taler.net/",
+ exchangeBaseUrl = "https://exchange.test.taler.net/",
+ ): Promise<void> {
+ await withdrawTestBalance(this.ws, amount, bankBaseUrl, exchangeBaseUrl);
+ }
}
diff --git a/src/walletCoreApiHandler.ts b/src/walletCoreApiHandler.ts
index a16490d5a..7ab6a6284 100644
--- a/src/walletCoreApiHandler.ts
+++ b/src/walletCoreApiHandler.ts
@@ -21,7 +21,6 @@ import {
makeErrorDetails,
} from "./operations/errors";
import { TalerErrorCode } from "./TalerErrorCode";
-import { withdrawTestBalance } from "./headless/helpers";
import { codecForTransactionsRequest } from "./types/transactions";
import {
makeCodecForObject,
@@ -160,7 +159,7 @@ async function dispatchRequestInternal(
): Promise<Record<string, any>> {
switch (operation) {
case "withdrawTestkudos":
- await withdrawTestBalance(wallet);
+ await wallet.withdrawTestBalance();
return {};
case "getTransactions": {
const req = codecForTransactionsRequest().decode(payload);