aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2020-08-14 15:53:50 +0530
committerFlorian Dold <florian.dold@gmail.com>2020-08-14 15:53:50 +0530
commit953cd9dc41ff3d52d23fe77f4ba3c18281e9d58f (patch)
tree17ff47fea3651dad192beee5d32c5fd4c538fa39
parente3850158c249d890399fdb9e083ec7e654a8380f (diff)
nuke some console.log statements, test wallet testing functionality in integration test
-rw-r--r--packages/taler-integrationtests/src/harness.ts82
-rw-r--r--packages/taler-integrationtests/src/test-wallettesting.ts90
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts8
-rw-r--r--packages/taler-wallet-core/src/headless/helpers.ts4
-rw-r--r--packages/taler-wallet-core/src/i18n/index.ts5
-rw-r--r--packages/taler-wallet-core/src/index.ts71
-rw-r--r--packages/taler-wallet-core/src/operations/exchanges.ts10
-rw-r--r--packages/taler-wallet-core/src/operations/pay.ts14
-rw-r--r--packages/taler-wallet-core/src/operations/recoup.ts13
-rw-r--r--packages/taler-wallet-core/src/operations/refresh.ts8
-rw-r--r--packages/taler-wallet-core/src/operations/refund.ts4
-rw-r--r--packages/taler-wallet-core/src/operations/reserves.ts4
-rw-r--r--packages/taler-wallet-core/src/operations/testing.ts78
-rw-r--r--packages/taler-wallet-core/src/operations/tip.ts17
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts5
-rw-r--r--packages/taler-wallet-core/src/types/dbTypes.ts7
-rw-r--r--packages/taler-wallet-core/src/types/transactions.ts8
-rw-r--r--packages/taler-wallet-core/src/types/walletTypes.ts27
-rw-r--r--packages/taler-wallet-core/src/util/RequestThrottler.ts9
-rw-r--r--packages/taler-wallet-core/src/util/query.ts26
-rw-r--r--packages/taler-wallet-core/src/wallet.ts29
-rw-r--r--packages/taler-wallet-webextension/src/browserWorkerEntry.ts10
22 files changed, 361 insertions, 168 deletions
diff --git a/packages/taler-integrationtests/src/harness.ts b/packages/taler-integrationtests/src/harness.ts
index 8f9c540f6..d710feea4 100644
--- a/packages/taler-integrationtests/src/harness.ts
+++ b/packages/taler-integrationtests/src/harness.ts
@@ -29,6 +29,7 @@ import * as fs from "fs";
import * as path from "path";
import * as os from "os";
import * as http from "http";
+import { deepStrictEqual } from "assert";
import { ChildProcess, spawn } from "child_process";
import {
Configuration,
@@ -53,6 +54,18 @@ import {
ConfirmPayRequest,
ConfirmPayResult,
codecForConfirmPayResult,
+ IntegrationTestArgs,
+ TestPayArgs,
+ BalancesResponse,
+ codecForBalancesResponse,
+ encodeCrock,
+ getRandomBytes,
+ EddsaKeyPair,
+ eddsaGetPublic,
+ createEddsaKeyPair,
+ TransactionsResponse,
+ codecForTransactionsResponse,
+ WithdrawTestBalanceRequest,
} from "taler-wallet-core";
import { URL } from "url";
import axios from "axios";
@@ -63,14 +76,6 @@ import {
PostOrderResponse,
MerchantOrderPrivateStatusResponse,
} from "./merchantApiTypes";
-import {
- EddsaKeyPair,
- getRandomBytes,
- encodeCrock,
- eddsaGetPublic,
- createEddsaKeyPair,
-} from "taler-wallet-core/lib/crypto/talerCrypto";
-import { WithdrawalDetails } from "taler-wallet-core/lib/types/transactions";
const exec = util.promisify(require("child_process").exec);
@@ -277,6 +282,10 @@ export class GlobalTestState {
}
}
+ assertDeepEqual(actual: any, expected: any): asserts actual is any {
+ deepStrictEqual(actual, expected);
+ }
+
assertAmountEquals(
amtExpected: string | AmountJson,
amtActual: string | AmountJson,
@@ -521,6 +530,10 @@ export class BankService {
config.setString("bank", "suggested_exchange_payto", exchangePayto);
}
+ get baseUrl(): string {
+ return `http://localhost:${this.bankConfig.httpPort}/`;
+ }
+
async createExchangeAccount(
accountName: string,
password: string,
@@ -890,11 +903,10 @@ export interface MerchantConfig {
database: string;
}
-
export interface PrivateOrderStatusQuery {
- instance?: string,
- orderId: string,
- sessionId?: string,
+ instance?: string;
+ orderId: string;
+ sessionId?: string;
}
export class MerchantService {
@@ -993,7 +1005,9 @@ export class MerchantService {
});
}
- async queryPrivateOrderStatus(query: PrivateOrderStatusQuery): Promise<MerchantOrderPrivateStatusResponse> {
+ async queryPrivateOrderStatus(
+ query: PrivateOrderStatusQuery,
+ ): Promise<MerchantOrderPrivateStatusResponse> {
const reqUrl = new URL(
`private/orders/${query.orderId}`,
this.makeInstanceBaseUrl(query.instance),
@@ -1215,6 +1229,46 @@ export class WalletCli {
throw new OperationFailedError(resp.error);
}
+ async getBalances(): Promise<BalancesResponse> {
+ const resp = await this.apiRequest("getBalances", {});
+ if (resp.type === "response") {
+ return codecForBalancesResponse().decode(resp.result);
+ }
+ throw new OperationFailedError(resp.error);
+ }
+
+ async getTransactions(): Promise<TransactionsResponse> {
+ const resp = await this.apiRequest("getTransactions", {});
+ if (resp.type === "response") {
+ return codecForTransactionsResponse().decode(resp.result);
+ }
+ throw new OperationFailedError(resp.error);
+ }
+
+ async runIntegrationtest(args: IntegrationTestArgs): Promise<void> {
+ const resp = await this.apiRequest("runIntegrationtest", args);
+ if (resp.type === "response") {
+ return;
+ }
+ throw new OperationFailedError(resp.error);
+ }
+
+ async testPay(args: TestPayArgs): Promise<void> {
+ const resp = await this.apiRequest("testPay", args);
+ if (resp.type === "response") {
+ return;
+ }
+ throw new OperationFailedError(resp.error);
+ }
+
+ async withdrawTestBalance(args: WithdrawTestBalanceRequest): Promise<void> {
+ const resp = await this.apiRequest("withdrawTestBalance", args);
+ if (resp.type === "response") {
+ return;
+ }
+ throw new OperationFailedError(resp.error);
+ }
+
async getWithdrawalDetailsForUri(
req: GetWithdrawalDetailsForUriRequest,
): Promise<WithdrawUriInfoResponse> {
@@ -1222,6 +1276,6 @@ export class WalletCli {
if (resp.type === "response") {
return codecForWithdrawUriInfoResponse().decode(resp.result);
}
- throw new OperationFailedError(resp.error);
+ throw new OperationFailedError(resp.error);
}
}
diff --git a/packages/taler-integrationtests/src/test-wallettesting.ts b/packages/taler-integrationtests/src/test-wallettesting.ts
new file mode 100644
index 000000000..de1f1e228
--- /dev/null
+++ b/packages/taler-integrationtests/src/test-wallettesting.ts
@@ -0,0 +1,90 @@
+/*
+ This file is part of GNU Taler
+ (C) 2020 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/>
+ */
+
+/**
+ * Integration test for the wallet testing functionality used by the exchange
+ * test cases.
+ */
+
+/**
+ * Imports.
+ */
+import { runTest, GlobalTestState } from "./harness";
+import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
+
+/**
+ * Run test for basic, bank-integrated withdrawal.
+ */
+runTest(async (t: GlobalTestState) => {
+ const {
+ wallet,
+ bank,
+ exchange,
+ merchant,
+ } = await createSimpleTestkudosEnvironment(t);
+
+ await wallet.runIntegrationtest({
+ amountToSpend: "TESTKUDOS:5",
+ amountToWithdraw: "TESTKUDOS:10",
+ bankBaseUrl: bank.baseUrl,
+ exchangeBaseUrl: exchange.baseUrl,
+ merchantApiKey: "sandbox",
+ merchantBaseUrl: merchant.makeInstanceBaseUrl(),
+ });
+
+ let txns = await wallet.getTransactions();
+ console.log(JSON.stringify(txns, undefined, 2));
+ let txTypes = txns.transactions.map((x) => x.type);
+
+ t.assertDeepEqual(txTypes, [
+ "withdrawal",
+ "payment",
+ "withdrawal",
+ "payment",
+ "refund",
+ "payment",
+ ]);
+
+ wallet.deleteDatabase();
+
+ await wallet.withdrawTestBalance({
+ amount: "TESTKUDOS:10",
+ bankBaseUrl: bank.baseUrl,
+ exchangeBaseUrl: exchange.baseUrl,
+ });
+
+ await wallet.runUntilDone();
+
+ await wallet.testPay({
+ amount: "TESTKUDOS:5",
+ merchantApiKey: "sandbox",
+ merchantBaseUrl: merchant.makeInstanceBaseUrl(),
+ summary: "foo",
+ });
+
+ await wallet.runUntilDone();
+
+ txns = await wallet.getTransactions();
+ console.log(JSON.stringify(txns, undefined, 2));
+ txTypes = txns.transactions.map((x) => x.type);
+
+ t.assertDeepEqual(txTypes, [
+ "withdrawal",
+ "payment",
+ ]);
+
+ await t.shutdown();
+});
diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
index 802a153ff..7d322877a 100644
--- a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
@@ -203,21 +203,21 @@ export class CryptoApi {
handleWorkerError(ws: WorkerState, e: any): void {
if (ws.currentWorkItem) {
- console.error(
+ logger.error(
`error in worker during ${ws.currentWorkItem.operation}`,
e,
);
} else {
- console.error("error in worker", e);
+ logger.error("error in worker", e);
}
- console.error(e.message);
+ logger.error(e.message);
try {
if (ws.w) {
ws.w.terminate();
ws.w = null;
}
} catch (e) {
- console.error(e);
+ logger.error(e);
}
if (ws.currentWorkItem !== null) {
ws.currentWorkItem.reject(e);
diff --git a/packages/taler-wallet-core/src/headless/helpers.ts b/packages/taler-wallet-core/src/headless/helpers.ts
index 953493299..1141ad25e 100644
--- a/packages/taler-wallet-core/src/headless/helpers.ts
+++ b/packages/taler-wallet-core/src/headless/helpers.ts
@@ -105,7 +105,7 @@ export async function getDefaultNodeWallet(
}
const myVersionChange = (): Promise<void> => {
- console.error("version change requested, should not happen");
+ logger.error("version change requested, should not happen");
throw Error();
};
@@ -119,7 +119,7 @@ export async function getDefaultNodeWallet(
require("worker_threads");
workerFactory = new NodeThreadCryptoWorkerFactory();
} catch (e) {
- console.log(
+ logger.warn(
"worker threads not available, falling back to synchronous workers",
);
workerFactory = new SynchronousCryptoWorkerFactory();
diff --git a/packages/taler-wallet-core/src/i18n/index.ts b/packages/taler-wallet-core/src/i18n/index.ts
index b248d2666..c5b70b1fd 100644
--- a/packages/taler-wallet-core/src/i18n/index.ts
+++ b/packages/taler-wallet-core/src/i18n/index.ts
@@ -26,6 +26,9 @@ export { strings } from "./strings";
// @ts-ignore: no type decl for this library
import * as jedLib from "jed";
+import { Logger } from "../util/logging";
+
+const logger = new Logger("i18n/index.ts");
export let jed: any = undefined;
@@ -38,7 +41,7 @@ export function setupI18n(lang: string): any {
if (!strings[lang]) {
lang = "en-US";
- console.log(`language ${lang} not found, defaulting to english`);
+ logger.warn(`language ${lang} not found, defaulting to english`);
}
jed = new jedLib.Jed(strings[lang]);
}
diff --git a/packages/taler-wallet-core/src/index.ts b/packages/taler-wallet-core/src/index.ts
index 1d5dc493b..193152abe 100644
--- a/packages/taler-wallet-core/src/index.ts
+++ b/packages/taler-wallet-core/src/index.ts
@@ -19,59 +19,48 @@
*/
export { Wallet } from "./wallet";
+
+// Errors
+export { TalerErrorCode } from "./TalerErrorCode";
+export * from "./operations/errors";
+
+// Utils for using the wallet under node
+export { NodeHttpLib } from "./headless/NodeHttpLib";
export {
getDefaultNodeWallet,
DefaultNodeWalletArgs,
} from "./headless/helpers";
-export { Amounts, AmountJson } from "./util/amounts";
-export { Logger } from "./util/logging";
-
-export * from "./crypto/talerCrypto";
-export {
- OperationFailedAndReportedError,
- OperationFailedError,
- makeErrorDetails,
-} from "./operations/errors";
-
-export * from "./types/walletTypes";
-
-export * from "./types/talerTypes";
-
-export * from "./util/taleruri";
-
-export * from "./util/time";
-
-export * from "./util/codec";
-
-export { NodeHttpLib } from "./headless/NodeHttpLib";
-
-export * from "./util/payto";
-
-export * from "./util/testvectors";
export * from "./operations/versions";
-export type { CryptoWorker } from "./crypto/workers/cryptoWorker";
-export { CryptoWorkerFactory, CryptoApi } from "./crypto/workers/cryptoApi";
-
-export * from "./util/http";
-
-export { TalerErrorCode } from "./TalerErrorCode";
-
-export * from "./util/query";
-
-export { CryptoImplementation } from "./crypto/workers/cryptoImplementation";
-
export * from "./db";
-export * from "./util/promiseUtils";
-
+// Internationalization
export * from "./i18n";
+// Crypto and crypto workers
export * from "./crypto/workers/nodeThreadWorker";
+export { CryptoImplementation } from "./crypto/workers/cryptoImplementation";
+export type { CryptoWorker } from "./crypto/workers/cryptoWorker";
+export { CryptoWorkerFactory, CryptoApi } from "./crypto/workers/cryptoApi";
+export * from "./crypto/talerCrypto";
-export * from "./types/notifications";
-
+// Util functionality
+export { Amounts, AmountJson } from "./util/amounts";
+export { Logger } from "./util/logging";
export { Configuration } from "./util/talerconfig";
+export { URL } from "./util/url";
+export * from "./util/codec";
+export * from "./util/promiseUtils";
+export * from "./util/query";
+export * from "./util/http";
+export * from "./util/payto";
+export * from "./util/testvectors";
+export * from "./util/taleruri";
+export * from "./util/time";
-export { URL } from "./util/url"; \ No newline at end of file
+// Types
+export * from "./types/talerTypes";
+export * from "./types/walletTypes";
+export * from "./types/notifications";
+export * from "./types/transactions"
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts
index a7771f6d2..d40dd7883 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -175,7 +175,7 @@ async function updateExchangeWithKeys(
async (tx) => {
const r = await tx.get(Stores.exchanges, baseUrl);
if (!r) {
- console.warn(`exchange ${baseUrl} no longer present`);
+ logger.warn(`exchange ${baseUrl} no longer present`);
return;
}
if (r.details) {
@@ -222,10 +222,10 @@ async function updateExchangeWithKeys(
if (oldDenom.isRevoked) {
// We already marked the denomination as revoked,
// this implies we revoked all coins
- console.log("denom already revoked");
+ logger.trace("denom already revoked");
continue;
}
- console.log("revoking denom", recoupInfo.h_denom_pub);
+ logger.trace("revoking denom", recoupInfo.h_denom_pub);
oldDenom.isRevoked = true;
await tx.put(Stores.denominations, oldDenom);
const affectedCoins = await tx
@@ -236,7 +236,7 @@ async function updateExchangeWithKeys(
}
}
if (newlyRevokedCoinPubs.length != 0) {
- console.log("recouping coins", newlyRevokedCoinPubs);
+ logger.trace("recouping coins", newlyRevokedCoinPubs);
await createRecoupGroup(ws, tx, newlyRevokedCoinPubs);
}
},
@@ -246,7 +246,7 @@ async function updateExchangeWithKeys(
// Asynchronously start recoup. This doesn't need to finish
// for the exchange update to be considered finished.
processRecoupGroup(ws, recoupGroupId).catch((e) => {
- console.log("error while recouping coins:", e);
+ logger.error("error while recouping coins:", e);
});
}
diff --git a/packages/taler-wallet-core/src/operations/pay.ts b/packages/taler-wallet-core/src/operations/pay.ts
index 0576f7eab..c3dd6c6d3 100644
--- a/packages/taler-wallet-core/src/operations/pay.ts
+++ b/packages/taler-wallet-core/src/operations/pay.ts
@@ -353,7 +353,7 @@ async function getCoinsForPayment(
throw Error("db inconsistent");
}
if (denom.value.currency !== currency) {
- console.warn(
+ logger.warn(
`same pubkey for different currencies at exchange ${exchange.baseUrl}`,
);
continue;
@@ -539,7 +539,7 @@ async function incrementPurchasePayRetry(
proposalId: string,
err: OperationErrorDetails | undefined,
): Promise<void> {
- console.log("incrementing purchase pay retry with error", err);
+ logger.warn("incrementing purchase pay retry with error", err);
await ws.db.runWithWriteTransaction([Stores.purchases], async (tx) => {
const pr = await tx.get(Stores.purchases, proposalId);
if (!pr) {
@@ -693,7 +693,7 @@ async function processDownloadProposalImpl(
fulfillmentUrl,
);
if (differentPurchase) {
- console.log("repurchase detected");
+ logger.warn("repurchase detected");
p.proposalStatus = ProposalStatus.REPURCHASE;
p.repurchaseProposalId = differentPurchase.proposalId;
await tx.put(Stores.proposals, p);
@@ -814,7 +814,7 @@ export async function submitPay(
merchantPub,
);
if (!valid) {
- console.error("merchant payment signature invalid");
+ logger.error("merchant payment signature invalid");
// FIXME: properly display error
throw Error("merchant payment signature invalid");
}
@@ -826,7 +826,7 @@ export async function submitPay(
if (isFirst) {
const ar = purchase.contractData.autoRefund;
if (ar) {
- console.log("auto_refund present");
+ logger.info("auto_refund present");
purchase.refundStatusRequested = true;
purchase.refundStatusRetryInfo = initRetryInfo();
purchase.lastRefundStatusError = undefined;
@@ -899,7 +899,7 @@ export async function preparePayForUri(
if (!existingProposalId) {
throw Error("invalid proposal state");
}
- console.log("using existing purchase for same product");
+ logger.trace("using existing purchase for same product");
proposal = await ws.db.get(Stores.proposals, existingProposalId);
if (!proposal) {
throw Error("existing proposal is in wrong state");
@@ -907,7 +907,7 @@ export async function preparePayForUri(
}
const d = proposal.download;
if (!d) {
- console.error("bad proposal", proposal);
+ logger.error("bad proposal", proposal);
throw Error("proposal is in invalid state");
}
const contractData = d.contractData;
diff --git a/packages/taler-wallet-core/src/operations/recoup.ts b/packages/taler-wallet-core/src/operations/recoup.ts
index cc91ab0e9..f855a28cb 100644
--- a/packages/taler-wallet-core/src/operations/recoup.ts
+++ b/packages/taler-wallet-core/src/operations/recoup.ts
@@ -51,6 +51,9 @@ import { getTimestampNow } from "../util/time";
import { guardOperationException } from "./errors";
import { readSuccessResponseJsonOrThrow } from "../util/http";
import { URL } from "../util/url";
+import { Logger } from "../util/logging";
+
+const logger = new Logger("operations/recoup.ts");
async function incrementRecoupRetry(
ws: InternalWalletState,
@@ -207,7 +210,7 @@ async function recoupWithdrawCoin(
});
forceQueryReserve(ws, reserve.reservePub).catch((e) => {
- console.log("re-querying reserve after recoup failed:", e);
+ logger.error("re-querying reserve after recoup failed:", e);
});
}
@@ -224,7 +227,7 @@ async function recoupRefreshCoin(
const recoupRequest = await ws.cryptoApi.createRecoupRequest(coin);
const reqUrl = new URL(`/coins/${coin.coinPub}/recoup`, coin.exchangeBaseUrl);
- console.log("making recoup request");
+ logger.trace("making recoup request");
const resp = await ws.http.postJson(reqUrl.href, recoupRequest);
const recoupConfirmation = await readSuccessResponseJsonOrThrow(
@@ -270,7 +273,7 @@ async function recoupRefreshCoin(
oldCoin.currentAmount,
recoupGroup.oldAmountPerCoin[coinIdx],
).amount;
- console.log(
+ logger.trace(
"recoup: setting old coin amount to",
Amounts.stringify(oldCoin.currentAmount),
);
@@ -317,14 +320,12 @@ async function processRecoupGroupImpl(
if (forceNow) {
await resetRecoupGroupRetry(ws, recoupGroupId);
}
- console.log("in processRecoupGroupImpl");
const recoupGroup = await ws.db.get(Stores.recoupGroups, recoupGroupId);
if (!recoupGroup) {
return;
}
- console.log(recoupGroup);
if (recoupGroup.timestampFinished) {
- console.log("recoup group finished");
+ logger.trace("recoup group finished");
return;
}
const ps = recoupGroup.coinPubs.map((x, i) =>
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts
index 646bc2edf..52325281b 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -188,7 +188,7 @@ async function refreshCreateSession(
}
const r = Amounts.sub(c.currentAmount, refreshSession.amountRefreshInput);
if (r.saturated) {
- console.log("can't refresh coin, no amount left");
+ logger.warn("can't refresh coin, no amount left");
return;
}
c.currentAmount = r.amount;
@@ -387,7 +387,7 @@ async function refreshReveal(
async (tx) => {
const rg = await tx.get(Stores.refreshGroups, refreshGroupId);
if (!rg) {
- console.log("no refresh session found");
+ logger.warn("no refresh session found");
return;
}
const rs = rg.refreshSessionPerCoin[coinIndex];
@@ -395,7 +395,7 @@ async function refreshReveal(
return;
}
if (rs.finishedTimestamp) {
- console.log("refresh session already finished");
+ logger.warn("refresh session already finished");
return;
}
rs.finishedTimestamp = getTimestampNow();
@@ -417,7 +417,7 @@ async function refreshReveal(
await tx.put(Stores.refreshGroups, rg);
},
);
- console.log("refresh finished (end of reveal)");
+ logger.trace("refresh finished (end of reveal)");
ws.notify({
type: NotificationType.RefreshRevealed,
});
diff --git a/packages/taler-wallet-core/src/operations/refund.ts b/packages/taler-wallet-core/src/operations/refund.ts
index 9ee71012e..fb39aa638 100644
--- a/packages/taler-wallet-core/src/operations/refund.ts
+++ b/packages/taler-wallet-core/src/operations/refund.ts
@@ -50,7 +50,7 @@ import {
AmountString,
} from "../types/talerTypes";
import { guardOperationException } from "./errors";
-import { getTimestampNow } from "../util/time";
+import { getTimestampNow, Timestamp } from "../util/time";
import { Logger } from "../util/logging";
import { readSuccessResponseJsonOrThrow } from "../util/http";
import { TransactionHandle } from "../util/query";
@@ -142,6 +142,7 @@ async function applySuccessfulRefund(
p.refunds[refundKey] = {
type: RefundState.Applied,
+ obtainedTime: getTimestampNow(),
executionTime: r.execution_time,
refundAmount: Amounts.parseOrThrow(r.refund_amount),
refundFee: denom.feeRefund,
@@ -191,6 +192,7 @@ async function storePendingRefund(
p.refunds[refundKey] = {
type: RefundState.Pending,
+ obtainedTime: getTimestampNow(),
executionTime: r.execution_time,
refundAmount: Amounts.parseOrThrow(r.refund_amount),
refundFee: denom.feeRefund,
diff --git a/packages/taler-wallet-core/src/operations/reserves.ts b/packages/taler-wallet-core/src/operations/reserves.ts
index 060226cab..fb525da45 100644
--- a/packages/taler-wallet-core/src/operations/reserves.ts
+++ b/packages/taler-wallet-core/src/operations/reserves.ts
@@ -178,7 +178,7 @@ export async function createReserve(
const exchangeInfo = await updateExchangeFromUrl(ws, req.exchange);
const exchangeDetails = exchangeInfo.details;
if (!exchangeDetails) {
- console.log(exchangeDetails);
+ logger.trace(exchangeDetails);
throw Error("exchange not updated");
}
const { isAudited, isTrusted } = await getExchangeTrust(ws, exchangeInfo);
@@ -576,7 +576,7 @@ async function processReserveImpl(
): Promise<void> {
const reserve = await ws.db.get(Stores.reserves, reservePub);
if (!reserve) {
- console.log("not processing reserve: reserve does not exist");
+ logger.trace("not processing reserve: reserve does not exist");
return;
}
if (!forceNow) {
diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts
index 629cd92ff..f1b2d98ff 100644
--- a/packages/taler-wallet-core/src/operations/testing.ts
+++ b/packages/taler-wallet-core/src/operations/testing.ts
@@ -269,11 +269,11 @@ async function makePayment(
"taler://fulfillment-success/thx",
);
- console.log("created order with orderId", orderResp.orderId);
+ logger.trace("created order with orderId", orderResp.orderId);
let paymentStatus = await checkPayment(http, merchant, orderResp.orderId);
- console.log("payment status", paymentStatus);
+ logger.trace("payment status", paymentStatus);
const talerPayUri = paymentStatus.taler_pay_uri;
if (!talerPayUri) {
@@ -282,7 +282,7 @@ async function makePayment(
const preparePayResult = await wallet.preparePayForUri(talerPayUri);
- console.log("prepare pay result", preparePayResult);
+ logger.trace("prepare pay result", preparePayResult);
if (preparePayResult.status != "payment-possible") {
throw Error("payment not possible");
@@ -293,11 +293,11 @@ async function makePayment(
undefined,
);
- console.log("confirmPayResult", confirmPayResult);
+ logger.trace("confirmPayResult", confirmPayResult);
paymentStatus = await checkPayment(http, merchant, orderResp.orderId);
- console.log("payment status after wallet payment:", paymentStatus);
+ logger.trace("payment status after wallet payment:", paymentStatus);
if (paymentStatus.order_status !== "paid") {
throw Error("payment did not succeed");
@@ -318,26 +318,18 @@ export async function runIntegrationTest(
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 wallet.withdrawTestBalance(
- args.amountToWithdraw,
- args.bankBaseUrl,
- args.exchangeBaseUrl,
- );
+ await wallet.withdrawTestBalance({
+ amount: args.amountToWithdraw,
+ bankBaseUrl: args.bankBaseUrl,
+ exchangeBaseUrl: args.exchangeBaseUrl,
+ });
+ await wallet.runUntilDone();
logger.info("done withdrawing test balance");
- const balance = await myWallet.getBalances();
+ const balance = await wallet.getBalances();
- console.log(JSON.stringify(balance, null, 2));
+ logger.trace(JSON.stringify(balance, null, 2));
const myMerchant: MerchantBackendInfo = {
baseUrl: args.merchantBaseUrl,
@@ -353,26 +345,26 @@ export async function runIntegrationTest(
);
// Wait until the refresh is done
- await myWallet.runUntilDone();
+ await wallet.runUntilDone();
- console.log("withdrawing test balance for refund");
+ logger.trace("withdrawing test balance for refund");
const withdrawAmountTwo = Amounts.parseOrThrow(`${currency}:18`);
const spendAmountTwo = Amounts.parseOrThrow(`${currency}:7`);
const refundAmount = Amounts.parseOrThrow(`${currency}:6`);
const spendAmountThree = Amounts.parseOrThrow(`${currency}:3`);
- await myWallet.withdrawTestBalance(
- Amounts.stringify(withdrawAmountTwo),
- args.bankBaseUrl,
- args.exchangeBaseUrl,
- );
+ await wallet.withdrawTestBalance({
+ amount: Amounts.stringify(withdrawAmountTwo),
+ bankBaseUrl: args.bankBaseUrl,
+ exchangeBaseUrl: args.exchangeBaseUrl,
+ });
// Wait until the withdraw is done
- await myWallet.runUntilDone();
+ await wallet.runUntilDone();
const { orderId: refundOrderId } = await makePayment(
http,
- myWallet,
+ wallet,
myMerchant,
Amounts.stringify(spendAmountTwo),
"order that will be refunded",
@@ -386,22 +378,30 @@ export async function runIntegrationTest(
Amounts.stringify(refundAmount),
);
- console.log("refund URI", refundUri);
+ logger.trace("refund URI", refundUri);
- await myWallet.applyRefund(refundUri);
+ await wallet.applyRefund(refundUri);
+
+ logger.trace("integration test: applied refund");
// Wait until the refund is done
- await myWallet.runUntilDone();
+ await wallet.runUntilDone();
+
+ logger.trace("integration test: making payment after refund");
await makePayment(
http,
- myWallet,
+ wallet,
myMerchant,
Amounts.stringify(spendAmountThree),
"payment after refund",
);
- await myWallet.runUntilDone();
+ logger.trace("integration test: make payment done");
+
+ await wallet.runUntilDone();
+
+ logger.trace("integration test: all done!");
}
export async function testPay(
@@ -409,8 +409,8 @@ export async function testPay(
wallet: Wallet,
args: TestPayArgs,
) {
- console.log("creating order");
- const merchant = { apikey: args.apikey, baseUrl: args.merchant };
+ logger.trace("creating order");
+ const merchant = { apikey: args.merchantApiKey, baseUrl: args.merchantBaseUrl };
const orderResp = await createOrder(
http,
merchant,
@@ -418,7 +418,7 @@ export async function testPay(
args.summary,
"taler://fulfillment-success/thank+you",
);
- console.log("created new order with order ID", orderResp.orderId);
+ logger.trace("created new order with order ID", orderResp.orderId);
const checkPayResp = await checkPayment(http, merchant, orderResp.orderId);
const talerPayUri = checkPayResp.taler_pay_uri;
if (!talerPayUri) {
@@ -426,7 +426,7 @@ export async function testPay(
process.exit(1);
return;
}
- console.log("taler pay URI:", talerPayUri);
+ logger.trace("taler pay URI:", talerPayUri);
const result = await wallet.preparePayForUri(talerPayUri);
if (result.status !== PreparePayResultType.PaymentPossible) {
throw Error(`unexpected prepare pay status: ${result.status}`);
diff --git a/packages/taler-wallet-core/src/operations/tip.ts b/packages/taler-wallet-core/src/operations/tip.ts
index 84cfa570a..6dee9c87e 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -45,6 +45,9 @@ import { NotificationType } from "../types/notifications";
import { getTimestampNow } from "../util/time";
import { readSuccessResponseJsonOrThrow } from "../util/http";
import { URL } from "../util/url";
+import { Logger } from "../util/logging";
+
+const logger = new Logger("operations/tip.ts");
export async function getTipStatus(
ws: InternalWalletState,
@@ -57,13 +60,13 @@ export async function getTipStatus(
const tipStatusUrl = new URL("tip-pickup", res.merchantBaseUrl);
tipStatusUrl.searchParams.set("tip_id", res.merchantTipId);
- console.log("checking tip status from", tipStatusUrl.href);
+ logger.trace("checking tip status from", tipStatusUrl.href);
const merchantResp = await ws.http.get(tipStatusUrl.href);
const tipPickupStatus = await readSuccessResponseJsonOrThrow(
merchantResp,
codecForTipPickupGetResponse(),
);
- console.log("status", tipPickupStatus);
+ logger.trace(`status ${tipPickupStatus}`);
const amount = Amounts.parseOrThrow(tipPickupStatus.amount);
@@ -191,7 +194,7 @@ async function processTipImpl(
}
if (tipRecord.pickedUp) {
- console.log("tip already picked up");
+ logger.warn("tip already picked up");
return;
}
@@ -230,7 +233,7 @@ async function processTipImpl(
throw Error("invariant violated");
}
- console.log("got planchets for tip!");
+ logger.trace("got planchets for tip!");
// Planchets in the form that the merchant expects
const planchetsDetail: TipPlanchetDetail[] = tipRecord.planchets.map((p) => ({
@@ -248,9 +251,9 @@ async function processTipImpl(
if (merchantResp.status !== 200) {
throw Error(`unexpected status ${merchantResp.status} for tip-pickup`);
}
- console.log("got merchant resp:", merchantResp);
+ logger.trace("got merchant resp:", merchantResp);
} catch (e) {
- console.log("tipping failed", e);
+ logger.warn("tipping failed", e);
throw e;
}
@@ -331,7 +334,7 @@ export async function acceptTip(
): Promise<void> {
const tipRecord = await ws.db.get(Stores.tips, tipId);
if (!tipRecord) {
- console.log("tip not found");
+ logger.error("tip not found");
return;
}
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 5521dda90..e17dfac3a 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -25,7 +25,7 @@ import {
RefundState,
} from "../types/dbTypes";
import { Amounts, AmountJson } from "../util/amounts";
-import { timestampCmp } from "../util/time";
+import { timestampCmp, Timestamp } from "../util/time";
import {
TransactionsRequest,
TransactionsResponse,
@@ -297,12 +297,13 @@ export async function getTransactions(
if (!r0) {
throw Error("invariant violated");
}
+ let ts: Timestamp;
transactions.push({
type: TransactionType.Refund,
info,
refundedTransactionId: paymentTransactionId,
transactionId: refundTransactionId,
- timestamp: r0.executionTime,
+ timestamp: r0.obtainedTime,
amountEffective: Amounts.stringify(amountEffective),
amountRaw: Amounts.stringify(amountRaw),
pending: false,
diff --git a/packages/taler-wallet-core/src/types/dbTypes.ts b/packages/taler-wallet-core/src/types/dbTypes.ts
index 3c4c2a250..26e636e48 100644
--- a/packages/taler-wallet-core/src/types/dbTypes.ts
+++ b/packages/taler-wallet-core/src/types/dbTypes.ts
@@ -1164,7 +1164,14 @@ export type WalletRefundItem =
| WalletRefundAppliedItem;
export interface WalletRefundItemCommon {
+ // Execution time as claimed by the merchant
executionTime: Timestamp;
+
+ /**
+ * Time when the wallet became aware of the refund.
+ */
+ obtainedTime: Timestamp;
+
refundAmount: AmountJson;
refundFee: AmountJson;
diff --git a/packages/taler-wallet-core/src/types/transactions.ts b/packages/taler-wallet-core/src/types/transactions.ts
index f3192e5a4..e40031499 100644
--- a/packages/taler-wallet-core/src/types/transactions.ts
+++ b/packages/taler-wallet-core/src/types/transactions.ts
@@ -31,6 +31,8 @@ import {
buildCodecForObject,
codecOptional,
codecForString,
+ codecForList,
+ codecForAny,
} from "../util/codec";
export interface TransactionsRequest {
@@ -309,3 +311,9 @@ export const codecForTransactionsRequest = (): Codec<TransactionsRequest> =>
.property("currency", codecOptional(codecForString()))
.property("search", codecOptional(codecForString()))
.build("TransactionsRequest");
+
+// FIXME: do full validation here!
+export const codecForTransactionsResponse = (): Codec<TransactionsResponse> =>
+ buildCodecForObject<TransactionsResponse>()
+ .property("transactions", codecForList(codecForAny()))
+ .build("TransactionsResponse"); \ No newline at end of file
diff --git a/packages/taler-wallet-core/src/types/walletTypes.ts b/packages/taler-wallet-core/src/types/walletTypes.ts
index e64187e72..511d7766c 100644
--- a/packages/taler-wallet-core/src/types/walletTypes.ts
+++ b/packages/taler-wallet-core/src/types/walletTypes.ts
@@ -653,16 +653,16 @@ export interface GetExchangeTosResult {
}
export interface TestPayArgs {
- merchant: string;
- apikey: string;
+ merchantBaseUrl: string;
+ merchantApiKey: string;
amount: string;
summary: string;
}
export const codecForTestPayArgs = (): Codec<TestPayArgs> =>
buildCodecForObject<TestPayArgs>()
- .property("merchant", codecForString())
- .property("apikey", codecForString())
+ .property("merchantBaseUrl", codecForString())
+ .property("merchantApiKey", codecForString())
.property("amount", codecForString())
.property("summary", codecForString())
.build("TestPayArgs");
@@ -829,3 +829,22 @@ export interface CoreApiResponseError {
id: string;
error: OperationErrorDetails;
}
+
+export interface WithdrawTestBalanceRequest {
+ amount: string;
+ bankBaseUrl: string;
+ exchangeBaseUrl: string;
+}
+
+export const withdrawTestBalanceDefaults = {
+ amount: "TESTKUDOS:10",
+ bankBaseUrl: "https://bank.test.taler.net/",
+ exchangeBaseUrl: "https://exchange.test.taler.net/",
+};
+
+export const codecForWithdrawTestBalance = (): Codec<WithdrawTestBalanceRequest> =>
+ buildCodecForObject<WithdrawTestBalanceRequest>()
+ .property("amount", codecForString())
+ .property("bankBaseUrl", codecForString())
+ .property("exchangeBaseUrl", codecForString())
+ .build("WithdrawTestBalanceRequest");
diff --git a/packages/taler-wallet-core/src/util/RequestThrottler.ts b/packages/taler-wallet-core/src/util/RequestThrottler.ts
index 6f51a72bc..3b8f22f58 100644
--- a/packages/taler-wallet-core/src/util/RequestThrottler.ts
+++ b/packages/taler-wallet-core/src/util/RequestThrottler.ts
@@ -23,6 +23,9 @@
*/
import { getTimestampNow, timestampDifference } from "../util/time";
import { URL } from "./url";
+import { Logger } from "./logging";
+
+const logger = new Logger("RequestThrottler.ts");
/**
* Maximum request per second, per origin.
@@ -77,15 +80,15 @@ class OriginState {
applyThrottle(): boolean {
this.refill();
if (this.tokensSecond < 1) {
- console.log("request throttled (per second limit exceeded)");
+ logger.warn("request throttled (per second limit exceeded)");
return true;
}
if (this.tokensMinute < 1) {
- console.log("request throttled (per minute limit exceeded)");
+ logger.warn("request throttled (per minute limit exceeded)");
return true;
}
if (this.tokensHour < 1) {
- console.log("request throttled (per hour limit exceeded)");
+ logger.warn("request throttled (per hour limit exceeded)");
return true;
}
this.tokensSecond--;
diff --git a/packages/taler-wallet-core/src/util/query.ts b/packages/taler-wallet-core/src/util/query.ts
index f6e689f49..6571491a1 100644
--- a/packages/taler-wallet-core/src/util/query.ts
+++ b/packages/taler-wallet-core/src/util/query.ts
@@ -35,6 +35,10 @@ import {
Event,
IDBCursor,
} from "idb-bridge";
+import { Logger } from "./logging";
+
+
+const logger = new Logger("query.ts");
/**
* Exception that should be thrown by client code to abort a transaction.
@@ -72,9 +76,9 @@ function requestToPromise(req: IDBRequest): Promise<any> {
resolve(req.result);
};
req.onerror = () => {
- console.log("error in DB request", req.error);
+ console.error("error in DB request", req.error);
reject(req.error);
- console.log("Request failed:", stack);
+ console.error("Request failed:", stack);
};
});
}
@@ -341,14 +345,14 @@ function runWithTransaction<T>(
resolve(funResult);
};
tx.onerror = () => {
- console.error("error in transaction");
- console.error(stack);
+ logger.error("error in transaction");
+ logger.error(`${stack}`);
};
tx.onabort = () => {
if (tx.error) {
- console.error("Transaction aborted with error:", tx.error);
+ logger.error("Transaction aborted with error:", tx.error);
} else {
- console.log("Trasaction aborted (no error)");
+ logger.error("Trasaction aborted (no error)");
}
reject(TransactionAbort);
};
@@ -361,7 +365,7 @@ function runWithTransaction<T>(
})
.catch((e) => {
if (e == TransactionAbort) {
- console.info("aborting transaction");
+ logger.trace("aborting transaction");
} else {
console.error("Transaction failed:", e);
console.error(stack);
@@ -427,12 +431,12 @@ export function openDatabase(
return new Promise<IDBDatabase>((resolve, reject) => {
const req = idbFactory.open(databaseName, databaseVersion);
req.onerror = (e) => {
- console.log("taler database error", e);
+ logger.error("taler database error", e);
reject(new Error("database error"));
};
req.onsuccess = (e) => {
req.result.onversionchange = (evt: IDBVersionChangeEvent) => {
- console.log(
+ logger.info(
`handling live db version change from ${evt.oldVersion} to ${evt.newVersion}`,
);
req.result.close();
@@ -491,7 +495,7 @@ export class Database {
importDatabase(dump: any): Promise<void> {
const db = this.db;
- console.log("importing db", dump);
+ logger.info("importing db", dump);
return new Promise<void>((resolve, reject) => {
const tx = db.transaction(Array.from(db.objectStoreNames), "readwrite");
if (dump.stores) {
@@ -501,7 +505,7 @@ export class Database {
for (const key in dumpStore) {
objects.push(dumpStore[key]);
}
- console.log(`importing ${objects.length} records into ${storeName}`);
+ logger.info(`importing ${objects.length} records into ${storeName}`);
const store = tx.objectStore(storeName);
for (const obj of objects) {
store.put(obj);
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 0b3e2ed60..4b309dde3 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -86,6 +86,10 @@ import {
CoreApiResponse,
codecForPreparePayRequest,
codecForIntegrationTestArgs,
+ WithdrawTestBalanceRequest,
+ withdrawTestBalanceDefaults,
+ codecForWithdrawTestBalance,
+ codecForTestPayArgs,
} from "./types/walletTypes";
import { Logger } from "./util/logging";
@@ -313,7 +317,7 @@ export class Wallet {
}
});
this.runRetryLoop().catch((e) => {
- console.log("exception in wallet retry loop");
+ logger.error("exception in wallet retry loop");
reject(e);
});
});
@@ -377,7 +381,7 @@ export class Wallet {
numPending,
});
await Promise.race([timeout, this.latch.wait()]);
- console.log("timeout done");
+ logger.trace("timeout done");
} else {
// FIXME: maybe be a bit smarter about executing these
// operations in parallel?
@@ -899,11 +903,9 @@ export class Wallet {
}
async withdrawTestBalance(
- amount = "TESTKUDOS:10",
- bankBaseUrl = "https://bank.test.taler.net/",
- exchangeBaseUrl = "https://exchange.test.taler.net/",
+ req: WithdrawTestBalanceRequest,
): Promise<void> {
- await withdrawTestBalance(this.ws, amount, bankBaseUrl, exchangeBaseUrl);
+ await withdrawTestBalance(this.ws, req.amount, req.bankBaseUrl, req.exchangeBaseUrl);
}
async runIntegrationtest(args: IntegrationTestArgs): Promise<void> {
@@ -924,7 +926,16 @@ export class Wallet {
): Promise<Record<string, any>> {
switch (operation) {
case "withdrawTestkudos": {
- await this.withdrawTestBalance();
+ await this.withdrawTestBalance({
+ amount: "TESTKUDOS:10",
+ bankBaseUrl: "https://bank.test.taler.net/",
+ exchangeBaseUrl: "https://exchange.test.taler.net/",
+ });
+ return {};
+ }
+ case "withdrawTestBalance": {
+ const req = codecForWithdrawTestBalance().decode(payload);
+ await this.withdrawTestBalance(req);
return {};
}
case "runIntegrationtest": {
@@ -933,8 +944,8 @@ export class Wallet {
return {}
}
case "testPay": {
- const req = codecForIntegrationTestArgs().decode(payload);
- await this.runIntegrationtest(req);
+ const req = codecForTestPayArgs().decode(payload);
+ await this.testPay(req);
return {}
}
case "getTransactions": {
diff --git a/packages/taler-wallet-webextension/src/browserWorkerEntry.ts b/packages/taler-wallet-webextension/src/browserWorkerEntry.ts
index 77c38fda9..cb13582a2 100644
--- a/packages/taler-wallet-webextension/src/browserWorkerEntry.ts
+++ b/packages/taler-wallet-webextension/src/browserWorkerEntry.ts
@@ -22,7 +22,9 @@
* Imports.
*/
-import { CryptoImplementation } from "taler-wallet-core";
+import { CryptoImplementation, Logger } from "taler-wallet-core";
+
+const logger = new Logger("browserWorkerEntry.ts");
const worker: Worker = (self as any) as Worker;
@@ -42,7 +44,7 @@ async function handleRequest(
const result = (impl as any)[operation](...args);
worker.postMessage({ result, id });
} catch (e) {
- console.log("error during operation", e);
+ logger.error("error during operation", e);
return;
}
}
@@ -64,10 +66,6 @@ worker.onmessage = (msg: MessageEvent) => {
return;
}
- if (CryptoImplementation.enableTracing) {
- console.log("onmessage with", operation);
- }
-
handleRequest(operation, id, args).catch((e) => {
console.error("error in browsere worker", e);
});