summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2020-08-14 13:06:42 +0530
committerFlorian Dold <florian.dold@gmail.com>2020-08-14 13:06:42 +0530
commite3850158c249d890399fdb9e083ec7e654a8380f (patch)
tree3226a8cb652e38d8c9290914b7c30f8b8ac9345b
parentd5f894690ee554909c1f8b1b8179fa110784dc4f (diff)
downloadwallet-core-e3850158c249d890399fdb9e083ec7e654a8380f.tar.gz
wallet-core-e3850158c249d890399fdb9e083ec7e654a8380f.tar.bz2
wallet-core-e3850158c249d890399fdb9e083ec7e654a8380f.zip
re-implement integration test functionalty that will be used by the exchange for testing
-rw-r--r--packages/taler-wallet-android/src/index.ts3
-rw-r--r--packages/taler-wallet-cli/package.json1
-rw-r--r--packages/taler-wallet-cli/src/index.ts8
-rw-r--r--packages/taler-wallet-core/src/index.ts4
-rw-r--r--packages/taler-wallet-core/src/operations/testing.ts281
-rw-r--r--packages/taler-wallet-core/src/types/walletTypes.ts187
-rw-r--r--packages/taler-wallet-core/src/wallet.ts194
-rw-r--r--packages/taler-wallet-core/src/walletCoreApiHandler.ts318
-rw-r--r--packages/taler-wallet-webextension/src/wxBackend.ts9
-rw-r--r--pnpm-lock.yaml2
10 files changed, 665 insertions, 342 deletions
diff --git a/packages/taler-wallet-android/src/index.ts b/packages/taler-wallet-android/src/index.ts
index 4430848c3..07d15d584 100644
--- a/packages/taler-wallet-android/src/index.ts
+++ b/packages/taler-wallet-android/src/index.ts
@@ -38,7 +38,6 @@ import {
WalletNotification,
WALLET_EXCHANGE_PROTOCOL_VERSION,
WALLET_MERCHANT_PROTOCOL_VERSION,
- handleCoreApiRequest,
} from "taler-wallet-core";
import fs from "fs";
@@ -229,7 +228,7 @@ class AndroidWalletMessageHandler {
}
default: {
const wallet = await this.wp.promise;
- return await handleCoreApiRequest(wallet, operation, id, args);
+ return await wallet.handleCoreApiRequest(operation, id, args);
}
}
}
diff --git a/packages/taler-wallet-cli/package.json b/packages/taler-wallet-cli/package.json
index 1870aa296..72a737d40 100644
--- a/packages/taler-wallet-cli/package.json
+++ b/packages/taler-wallet-cli/package.json
@@ -43,6 +43,7 @@
"typescript": "^3.9.7"
},
"dependencies": {
+ "axios": "^0.19.2",
"source-map-support": "^0.5.19",
"taler-wallet-core": "workspace:*",
"tslib": "^2.0.0"
diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts
index a32ed2267..94f01ba80 100644
--- a/packages/taler-wallet-cli/src/index.ts
+++ b/packages/taler-wallet-cli/src/index.ts
@@ -26,7 +26,6 @@ import {
NodeHttpLib,
PreparePayResultType,
setDangerousTimetravel,
- handleCoreApiRequest,
classifyTalerUri,
TalerUriType,
decodeCrock,
@@ -34,10 +33,10 @@ import {
codecForList,
codecForString,
printTestVectors,
+ NodeThreadCryptoWorkerFactory,
+ CryptoApi,
} from "taler-wallet-core";
import * as clk from "./clk";
-import { NodeThreadCryptoWorkerFactory } from "taler-wallet-core/lib/crypto/workers/nodeThreadWorker";
-import { CryptoApi } from "taler-wallet-core/lib/crypto/workers/cryptoApi";
// This module also serves as the entry point for the crypto
// thread worker, and thus must expose these two handlers.
@@ -210,8 +209,7 @@ walletCli
console.error("Invalid JSON");
process.exit(1);
}
- const resp = await handleCoreApiRequest(
- wallet,
+ const resp = await wallet.handleCoreApiRequest(
args.api.operation,
"reqid-1",
requestJson,
diff --git a/packages/taler-wallet-core/src/index.ts b/packages/taler-wallet-core/src/index.ts
index 784c9d63b..1d5dc493b 100644
--- a/packages/taler-wallet-core/src/index.ts
+++ b/packages/taler-wallet-core/src/index.ts
@@ -37,8 +37,6 @@ export * from "./types/walletTypes";
export * from "./types/talerTypes";
-export * from "./walletCoreApiHandler";
-
export * from "./util/taleruri";
export * from "./util/time";
@@ -54,7 +52,7 @@ export * from "./util/testvectors";
export * from "./operations/versions";
export type { CryptoWorker } from "./crypto/workers/cryptoWorker";
-export type { CryptoWorkerFactory } from "./crypto/workers/cryptoApi";
+export { CryptoWorkerFactory, CryptoApi } from "./crypto/workers/cryptoApi";
export * from "./util/http";
diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts
index 3ccfafc93..629cd92ff 100644
--- a/packages/taler-wallet-core/src/operations/testing.ts
+++ b/packages/taler-wallet-core/src/operations/testing.ts
@@ -21,10 +21,19 @@ import {
checkSuccessResponseOrThrow,
} from "../util/http";
import { codecForAny } from "../util/codec";
-import { AmountString } from "../types/talerTypes";
+import {
+ AmountString,
+ CheckPaymentResponse,
+ codecForCheckPaymentResponse,
+} from "../types/talerTypes";
import { InternalWalletState } from "./state";
import { createTalerWithdrawReserve } from "./reserves";
import { URL } from "../util/url";
+import { Wallet } from "../wallet";
+import { Amounts } from "../util/amounts";
+import { NodeHttpLib } from "../headless/NodeHttpLib";
+import { getDefaultNodeWallet } from "../headless/helpers";
+import { TestPayArgs, PreparePayResultType, IntegrationTestArgs } from "../types/walletTypes";
const logger = new Logger("operations/testing.ts");
@@ -38,6 +47,11 @@ interface BankWithdrawalResponse {
withdrawal_id: string;
}
+interface MerchantBackendInfo {
+ baseUrl: string;
+ apikey: string;
+}
+
/**
* Generate a random alphanumeric ID. Does *not* use cryptographically
* secure randomness.
@@ -154,3 +168,268 @@ async function registerRandomBankUser(
await checkSuccessResponseOrThrow(resp);
return bankUser;
}
+
+async function refund(
+ http: HttpRequestLibrary,
+ merchantBackend: MerchantBackendInfo,
+ orderId: string,
+ reason: string,
+ refundAmount: string,
+): Promise<string> {
+ const reqUrl = new URL(
+ `private/orders/${orderId}/refund`,
+ merchantBackend.baseUrl,
+ );
+ const refundReq = {
+ order_id: orderId,
+ reason,
+ refund: refundAmount,
+ };
+ const resp = await http.postJson(reqUrl.href, refundReq, {
+ headers: {
+ Authorization: `ApiKey ${merchantBackend.apikey}`,
+ },
+ });
+ const r = await readSuccessResponseJsonOrThrow(resp, codecForAny());
+ const refundUri = r.taler_refund_uri;
+ if (!refundUri) {
+ throw Error("no refund URI in response");
+ }
+ return refundUri;
+}
+
+async function createOrder(
+ http: HttpRequestLibrary,
+ merchantBackend: MerchantBackendInfo,
+ 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", merchantBackend.baseUrl).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 http.postJson(reqUrl, orderReq, {
+ headers: {
+ Authorization: `ApiKey ${merchantBackend.apikey}`,
+ },
+ });
+ const r = await readSuccessResponseJsonOrThrow(resp, codecForAny());
+ const orderId = r.order_id;
+ if (!orderId) {
+ throw Error("no order id in response");
+ }
+ return { orderId };
+}
+
+async function checkPayment(
+ http: HttpRequestLibrary,
+ merchantBackend: MerchantBackendInfo,
+ orderId: string,
+): Promise<CheckPaymentResponse> {
+ const reqUrl = new URL(`/private/orders/${orderId}`, merchantBackend.baseUrl);
+ reqUrl.searchParams.set("order_id", orderId);
+ const resp = await http.get(reqUrl.href, {
+ headers: {
+ Authorization: `ApiKey ${merchantBackend.apikey}`,
+ },
+ });
+ return readSuccessResponseJsonOrThrow(resp, codecForCheckPaymentResponse());
+}
+
+interface BankUser {
+ username: string;
+ password: string;
+}
+
+interface BankWithdrawalResponse {
+ taler_withdraw_uri: string;
+ withdrawal_id: string;
+}
+
+async function makePayment(
+ http: HttpRequestLibrary,
+ wallet: Wallet,
+ merchant: MerchantBackendInfo,
+ amount: string,
+ summary: string,
+): Promise<{ orderId: string }> {
+ const orderResp = await createOrder(
+ http,
+ merchant,
+ amount,
+ summary,
+ "taler://fulfillment-success/thx",
+ );
+
+ console.log("created order with orderId", orderResp.orderId);
+
+ let paymentStatus = await checkPayment(http, merchant, 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 checkPayment(http, merchant, orderResp.orderId);
+
+ console.log("payment status after wallet payment:", paymentStatus);
+
+ if (paymentStatus.order_status !== "paid") {
+ throw Error("payment did not succeed");
+ }
+
+ return {
+ orderId: orderResp.orderId,
+ };
+}
+
+export async function runIntegrationTest(
+ http: HttpRequestLibrary,
+ wallet: Wallet,
+ 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 wallet.withdrawTestBalance(
+ args.amountToWithdraw,
+ args.bankBaseUrl,
+ args.exchangeBaseUrl,
+ );
+ logger.info("done withdrawing test balance");
+
+ const balance = await myWallet.getBalances();
+
+ console.log(JSON.stringify(balance, null, 2));
+
+ const myMerchant: MerchantBackendInfo = {
+ baseUrl: args.merchantBaseUrl,
+ apikey: args.merchantApiKey,
+ };
+
+ await makePayment(
+ http,
+ wallet,
+ myMerchant,
+ args.amountToSpend,
+ "hello world",
+ );
+
+ // Wait until the refresh is done
+ await myWallet.runUntilDone();
+
+ console.log("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,
+ );
+
+ // Wait until the withdraw is done
+ await myWallet.runUntilDone();
+
+ const { orderId: refundOrderId } = await makePayment(
+ http,
+ myWallet,
+ myMerchant,
+ Amounts.stringify(spendAmountTwo),
+ "order that will be refunded",
+ );
+
+ const refundUri = await refund(
+ http,
+ myMerchant,
+ 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(
+ http,
+ myWallet,
+ myMerchant,
+ Amounts.stringify(spendAmountThree),
+ "payment after refund",
+ );
+
+ await myWallet.runUntilDone();
+}
+
+export async function testPay(
+ http: HttpRequestLibrary,
+ wallet: Wallet,
+ args: TestPayArgs,
+) {
+ console.log("creating order");
+ const merchant = { apikey: args.apikey, baseUrl: args.merchant };
+ const orderResp = await createOrder(
+ http,
+ merchant,
+ args.amount,
+ args.summary,
+ "taler://fulfillment-success/thank+you",
+ );
+ console.log("created new order with order ID", orderResp.orderId);
+ const checkPayResp = await checkPayment(http, merchant, 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);
+ const result = await wallet.preparePayForUri(talerPayUri);
+ if (result.status !== PreparePayResultType.PaymentPossible) {
+ throw Error(`unexpected prepare pay status: ${result.status}`);
+ }
+ await wallet.confirmPay(result.proposalId, undefined);
+}
diff --git a/packages/taler-wallet-core/src/types/walletTypes.ts b/packages/taler-wallet-core/src/types/walletTypes.ts
index 8521af3ff..e64187e72 100644
--- a/packages/taler-wallet-core/src/types/walletTypes.ts
+++ b/packages/taler-wallet-core/src/types/walletTypes.ts
@@ -229,9 +229,7 @@ export const codecForConfirmPayResultPending = (): Codec<
.property("type", codecForConstString(ConfirmPayResultType.Pending))
.build("ConfirmPayResultPending");
-export const codecForConfirmPayResultDone = (): Codec<
- ConfirmPayResultDone
-> =>
+export const codecForConfirmPayResultDone = (): Codec<ConfirmPayResultDone> =>
buildCodecForObject<ConfirmPayResultDone>()
.property("type", codecForConstString(ConfirmPayResultType.Done))
.property("nextUrl", codecForString())
@@ -240,7 +238,10 @@ export const codecForConfirmPayResultDone = (): Codec<
export const codecForConfirmPayResult = (): Codec<ConfirmPayResult> =>
buildCodecForUnion<ConfirmPayResult>()
.discriminateOn("type")
- .alternative(ConfirmPayResultType.Pending, codecForConfirmPayResultPending())
+ .alternative(
+ ConfirmPayResultType.Pending,
+ codecForConfirmPayResultPending(),
+ )
.alternative(ConfirmPayResultType.Done, codecForConfirmPayResultDone())
.build("ConfirmPayResult");
@@ -650,3 +651,181 @@ export interface GetExchangeTosResult {
*/
acceptedEtag: string | undefined;
}
+
+export interface TestPayArgs {
+ merchant: string;
+ apikey: string;
+ amount: string;
+ summary: string;
+}
+
+export const codecForTestPayArgs = (): Codec<TestPayArgs> =>
+ buildCodecForObject<TestPayArgs>()
+ .property("merchant", codecForString())
+ .property("apikey", codecForString())
+ .property("amount", codecForString())
+ .property("summary", codecForString())
+ .build("TestPayArgs");
+
+export interface IntegrationTestArgs {
+ exchangeBaseUrl: string;
+ bankBaseUrl: string;
+ merchantBaseUrl: string;
+ merchantApiKey: string;
+ amountToWithdraw: string;
+ amountToSpend: string;
+}
+
+export const codecForIntegrationTestArgs = (): Codec<IntegrationTestArgs> =>
+ buildCodecForObject<IntegrationTestArgs>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("bankBaseUrl", codecForString())
+ .property("merchantBaseUrl", codecForString())
+ .property("merchantApiKey", codecForString())
+ .property("amountToSpend", codecForAmountString())
+ .property("amountToWithdraw", codecForAmountString())
+ .build("IntegrationTestArgs");
+
+export interface AddExchangeRequest {
+ exchangeBaseUrl: string;
+}
+
+export const codecForAddExchangeRequest = (): Codec<AddExchangeRequest> =>
+ buildCodecForObject<AddExchangeRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .build("AddExchangeRequest");
+
+export interface GetExchangeTosRequest {
+ exchangeBaseUrl: string;
+}
+
+export const codecForGetExchangeTosRequest = (): Codec<GetExchangeTosRequest> =>
+ buildCodecForObject<GetExchangeTosRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .build("GetExchangeTosRequest");
+
+export interface AcceptManualWithdrawalRequest {
+ exchangeBaseUrl: string;
+ amount: string;
+}
+
+export const codecForAcceptManualWithdrawalRequet = (): Codec<
+ AcceptManualWithdrawalRequest
+> =>
+ buildCodecForObject<AcceptManualWithdrawalRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("amount", codecForString())
+ .build("AcceptManualWithdrawalRequest");
+
+export interface GetWithdrawalDetailsForAmountRequest {
+ exchangeBaseUrl: string;
+ amount: string;
+}
+
+export interface AcceptBankIntegratedWithdrawalRequest {
+ talerWithdrawUri: string;
+ exchangeBaseUrl: string;
+}
+
+export const codecForAcceptBankIntegratedWithdrawalRequest = (): Codec<
+ AcceptBankIntegratedWithdrawalRequest
+> =>
+ buildCodecForObject<AcceptBankIntegratedWithdrawalRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("talerWithdrawUri", codecForString())
+ .build("AcceptBankIntegratedWithdrawalRequest");
+
+export const codecForGetWithdrawalDetailsForAmountRequest = (): Codec<
+ GetWithdrawalDetailsForAmountRequest
+> =>
+ buildCodecForObject<GetWithdrawalDetailsForAmountRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("amount", codecForString())
+ .build("GetWithdrawalDetailsForAmountRequest");
+
+export interface AcceptExchangeTosRequest {
+ exchangeBaseUrl: string;
+ etag: string;
+}
+
+export const codecForAcceptExchangeTosRequest = (): Codec<
+ AcceptExchangeTosRequest
+> =>
+ buildCodecForObject<AcceptExchangeTosRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("etag", codecForString())
+ .build("AcceptExchangeTosRequest");
+
+export interface ApplyRefundRequest {
+ talerRefundUri: string;
+}
+
+export const codecForApplyRefundRequest = (): Codec<ApplyRefundRequest> =>
+ buildCodecForObject<ApplyRefundRequest>()
+ .property("talerRefundUri", codecForString())
+ .build("ApplyRefundRequest");
+
+export interface GetWithdrawalDetailsForUriRequest {
+ talerWithdrawUri: string;
+}
+
+export const codecForGetWithdrawalDetailsForUri = (): Codec<
+ GetWithdrawalDetailsForUriRequest
+> =>
+ buildCodecForObject<GetWithdrawalDetailsForUriRequest>()
+ .property("talerWithdrawUri", codecForString())
+ .build("GetWithdrawalDetailsForUriRequest");
+
+export interface AbortProposalRequest {
+ proposalId: string;
+}
+
+export const codecForAbortProposalRequest = (): Codec<AbortProposalRequest> =>
+ buildCodecForObject<AbortProposalRequest>()
+ .property("proposalId", codecForString())
+ .build("AbortProposalRequest");
+
+export interface PreparePayRequest {
+ talerPayUri: string;
+}
+
+export const codecForPreparePayRequest = (): Codec<PreparePayRequest> =>
+ buildCodecForObject<PreparePayRequest>()
+ .property("talerPayUri", codecForString())
+ .build("PreparePay");
+
+export interface ConfirmPayRequest {
+ proposalId: string;
+ sessionId?: string;
+}
+
+export const codecForConfirmPayRequest = (): Codec<ConfirmPayRequest> =>
+ buildCodecForObject<ConfirmPayRequest>()
+ .property("proposalId", codecForString())
+ .property("sessionId", codecOptional(codecForString()))
+ .build("ConfirmPay");
+
+export type CoreApiResponse = CoreApiResponseSuccess | CoreApiResponseError;
+
+export type CoreApiEnvelope = CoreApiResponse | CoreApiNotification;
+
+export interface CoreApiNotification {
+ type: "notification";
+ payload: unknown;
+}
+
+export interface CoreApiResponseSuccess {
+ // To distinguish the message from notifications
+ type: "response";
+ operation: string;
+ id: string;
+ result: unknown;
+}
+
+export interface CoreApiResponseError {
+ // To distinguish the message from notifications
+ type: "error";
+ operation: string;
+ id: string;
+ error: OperationErrorDetails;
+}
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 4a409f58d..0b3e2ed60 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -70,6 +70,22 @@ import {
GetExchangeTosResult,
AcceptManualWithdrawalResult,
BalancesResponse,
+ TestPayArgs,
+ PreparePayResultType,
+ IntegrationTestArgs,
+ codecForAddExchangeRequest,
+ codecForGetWithdrawalDetailsForUri,
+ codecForAcceptManualWithdrawalRequet,
+ codecForGetWithdrawalDetailsForAmountRequest,
+ codecForAcceptExchangeTosRequest,
+ codecForApplyRefundRequest,
+ codecForAcceptBankIntegratedWithdrawalRequest,
+ codecForGetExchangeTosRequest,
+ codecForAbortProposalRequest,
+ codecForConfirmPayRequest,
+ CoreApiResponse,
+ codecForPreparePayRequest,
+ codecForIntegrationTestArgs,
} from "./types/walletTypes";
import { Logger } from "./util/logging";
@@ -107,13 +123,23 @@ import { WalletNotification, NotificationType } from "./types/notifications";
import { processPurchaseQueryRefund, applyRefund } from "./operations/refund";
import { durationMin, Duration } from "./util/time";
import { processRecoupGroup } from "./operations/recoup";
-import { OperationFailedAndReportedError } from "./operations/errors";
+import {
+ OperationFailedAndReportedError,
+ OperationFailedError,
+ makeErrorDetails,
+} from "./operations/errors";
import {
TransactionsRequest,
TransactionsResponse,
+ codecForTransactionsRequest,
} from "./types/transactions";
import { getTransactions } from "./operations/transactions";
-import { withdrawTestBalance } from "./operations/testing";
+import {
+ withdrawTestBalance,
+ runIntegrationTest,
+ testPay,
+} from "./operations/testing";
+import { TalerErrorCode } from ".";
const builtinCurrencies: CurrencyRecord[] = [
{
@@ -879,4 +905,168 @@ export class Wallet {
): Promise<void> {
await withdrawTestBalance(this.ws, amount, bankBaseUrl, exchangeBaseUrl);
}
+
+ async runIntegrationtest(args: IntegrationTestArgs): Promise<void> {
+ return runIntegrationTest(this.ws.http, this, args);
+ }
+
+ async testPay(args: TestPayArgs) {
+ return testPay(this.ws.http, this, args);
+ }
+
+ /**
+ * Implementation of the "wallet-core" API.
+ */
+
+ private async dispatchRequestInternal(
+ operation: string,
+ payload: unknown,
+ ): Promise<Record<string, any>> {
+ switch (operation) {
+ case "withdrawTestkudos": {
+ await this.withdrawTestBalance();
+ return {};
+ }
+ case "runIntegrationtest": {
+ const req = codecForIntegrationTestArgs().decode(payload);
+ await this.runIntegrationtest(req);
+ return {}
+ }
+ case "testPay": {
+ const req = codecForIntegrationTestArgs().decode(payload);
+ await this.runIntegrationtest(req);
+ return {}
+ }
+ case "getTransactions": {
+ const req = codecForTransactionsRequest().decode(payload);
+ return await this.getTransactions(req);
+ }
+ case "addExchange": {
+ const req = codecForAddExchangeRequest().decode(payload);
+ await this.updateExchangeFromUrl(req.exchangeBaseUrl);
+ return {};
+ }
+ case "listExchanges": {
+ return await this.getExchanges();
+ }
+ case "getWithdrawalDetailsForUri": {
+ const req = codecForGetWithdrawalDetailsForUri().decode(payload);
+ return await this.getWithdrawalDetailsForUri(req.talerWithdrawUri);
+ }
+ case "acceptManualWithdrawal": {
+ const req = codecForAcceptManualWithdrawalRequet().decode(payload);
+ const res = await this.acceptManualWithdrawal(
+ req.exchangeBaseUrl,
+ Amounts.parseOrThrow(req.amount),
+ );
+ return res;
+ }
+ case "getWithdrawalDetailsForAmount": {
+ const req = codecForGetWithdrawalDetailsForAmountRequest().decode(
+ payload,
+ );
+ return await this.getWithdrawalDetailsForAmount(
+ req.exchangeBaseUrl,
+ Amounts.parseOrThrow(req.amount),
+ );
+ }
+ case "getBalances": {
+ return await this.getBalances();
+ }
+ case "getPendingOperations": {
+ return await this.getPendingOperations();
+ }
+ case "setExchangeTosAccepted": {
+ const req = codecForAcceptExchangeTosRequest().decode(payload);
+ await this.acceptExchangeTermsOfService(
+ req.exchangeBaseUrl,
+ req.etag,
+ );
+ return {};
+ }
+ case "applyRefund": {
+ const req = codecForApplyRefundRequest().decode(payload);
+ return await this.applyRefund(req.talerRefundUri);
+ }
+ case "acceptBankIntegratedWithdrawal": {
+ const req = codecForAcceptBankIntegratedWithdrawalRequest().decode(
+ payload,
+ );
+ return await this.acceptWithdrawal(
+ req.talerWithdrawUri,
+ req.exchangeBaseUrl,
+ );
+ }
+ case "getExchangeTos": {
+ const req = codecForGetExchangeTosRequest().decode(payload);
+ return this.getExchangeTos(req.exchangeBaseUrl);
+ }
+ case "abortProposal": {
+ const req = codecForAbortProposalRequest().decode(payload);
+ await this.refuseProposal(req.proposalId);
+ return {};
+ }
+ case "retryPendingNow": {
+ await this.runPending(true);
+ return {};
+ }
+ case "preparePay": {
+ const req = codecForPreparePayRequest().decode(payload);
+ return await this.preparePayForUri(req.talerPayUri);
+ }
+ case "confirmPay": {
+ const req = codecForConfirmPayRequest().decode(payload);
+ return await this.confirmPay(req.proposalId, req.sessionId);
+ }
+ }
+ throw OperationFailedError.fromCode(
+ TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN,
+ "unknown operation",
+ {
+ operation,
+ },
+ );
+ }
+
+ /**
+ * Handle a request to the wallet-core API.
+ */
+ async handleCoreApiRequest(
+ operation: string,
+ id: string,
+ payload: unknown,
+ ): Promise<CoreApiResponse> {
+ try {
+ const result = await this.dispatchRequestInternal(operation, payload);
+ return {
+ type: "response",
+ operation,
+ id,
+ result,
+ };
+ } catch (e) {
+ if (
+ e instanceof OperationFailedError ||
+ e instanceof OperationFailedAndReportedError
+ ) {
+ return {
+ type: "error",
+ operation,
+ id,
+ error: e.operationError,
+ };
+ } else {
+ return {
+ type: "error",
+ operation,
+ id,
+ error: makeErrorDetails(
+ TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION,
+ `unexpected exception: ${e}`,
+ {},
+ ),
+ };
+ }
+ }
+ }
}
diff --git a/packages/taler-wallet-core/src/walletCoreApiHandler.ts b/packages/taler-wallet-core/src/walletCoreApiHandler.ts
deleted file mode 100644
index 5bc9005a8..000000000
--- a/packages/taler-wallet-core/src/walletCoreApiHandler.ts
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- 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/>
- */
-
-import { Wallet } from "./wallet";
-import {
- OperationFailedError,
- OperationFailedAndReportedError,
- makeErrorDetails,
-} from "./operations/errors";
-import { TalerErrorCode } from "./TalerErrorCode";
-import { codecForTransactionsRequest } from "./types/transactions";
-import {
- buildCodecForObject,
- codecForString,
- Codec,
- codecOptional,
-} from "./util/codec";
-import { Amounts } from "./util/amounts";
-import { OperationErrorDetails } from "./types/walletTypes";
-
-export interface AddExchangeRequest {
- exchangeBaseUrl: string;
-}
-
-export const codecForAddExchangeRequest = (): Codec<AddExchangeRequest> =>
- buildCodecForObject<AddExchangeRequest>()
- .property("exchangeBaseUrl", codecForString())
- .build("AddExchangeRequest");
-
-export interface GetExchangeTosRequest {
- exchangeBaseUrl: string;
-}
-
-export const codecForGetExchangeTosRequest = (): Codec<GetExchangeTosRequest> =>
- buildCodecForObject<GetExchangeTosRequest>()
- .property("exchangeBaseUrl", codecForString())
- .build("GetExchangeTosRequest");
-
-export interface AcceptManualWithdrawalRequest {
- exchangeBaseUrl: string;
- amount: string;
-}
-
-export const codecForAcceptManualWithdrawalRequet = (): Codec<
- AcceptManualWithdrawalRequest
-> =>
- buildCodecForObject<AcceptManualWithdrawalRequest>()
- .property("exchangeBaseUrl", codecForString())
- .property("amount", codecForString())
- .build("AcceptManualWithdrawalRequest");
-
-export interface GetWithdrawalDetailsForAmountRequest {
- exchangeBaseUrl: string;
- amount: string;
-}
-
-export interface AcceptBankIntegratedWithdrawalRequest {
- talerWithdrawUri: string;
- exchangeBaseUrl: string;
-}
-
-export const codecForAcceptBankIntegratedWithdrawalRequest = (): Codec<
- AcceptBankIntegratedWithdrawalRequest
-> =>
- buildCodecForObject<AcceptBankIntegratedWithdrawalRequest>()
- .property("exchangeBaseUrl", codecForString())
- .property("talerWithdrawUri", codecForString())
- .build("AcceptBankIntegratedWithdrawalRequest");
-
-export const codecForGetWithdrawalDetailsForAmountRequest = (): Codec<
- GetWithdrawalDetailsForAmountRequest
-> =>
- buildCodecForObject<GetWithdrawalDetailsForAmountRequest>()
- .property("exchangeBaseUrl", codecForString())
- .property("amount", codecForString())
- .build("GetWithdrawalDetailsForAmountRequest");
-
-export interface AcceptExchangeTosRequest {
- exchangeBaseUrl: string;
- etag: string;
-}
-
-export const codecForAcceptExchangeTosRequest = (): Codec<AcceptExchangeTosRequest> =>
- buildCodecForObject<AcceptExchangeTosRequest>()
- .property("exchangeBaseUrl", codecForString())
- .property("etag", codecForString())
- .build("AcceptExchangeTosRequest");
-
-export interface ApplyRefundRequest {
- talerRefundUri: string;
-}
-
-export const codecForApplyRefundRequest = (): Codec<ApplyRefundRequest> =>
- buildCodecForObject<ApplyRefundRequest>()
- .property("talerRefundUri", codecForString())
- .build("ApplyRefundRequest");
-
-export interface GetWithdrawalDetailsForUriRequest {
- talerWithdrawUri: string;
-}
-
-export const codecForGetWithdrawalDetailsForUri = (): Codec<
- GetWithdrawalDetailsForUriRequest
-> =>
- buildCodecForObject<GetWithdrawalDetailsForUriRequest>()
- .property("talerWithdrawUri", codecForString())
- .build("GetWithdrawalDetailsForUriRequest");
-
-export interface AbortProposalRequest {
- proposalId: string;
-}
-
-export const codecForAbortProposalRequest = (): Codec<AbortProposalRequest> =>
- buildCodecForObject<AbortProposalRequest>()
- .property("proposalId", codecForString())
- .build("AbortProposalRequest");
-
-export interface PreparePayRequest {
- talerPayUri: string;
-}
-
-const codecForPreparePayRequest = (): Codec<PreparePayRequest> =>
- buildCodecForObject<PreparePayRequest>()
- .property("talerPayUri", codecForString())
- .build("PreparePay");
-
-export interface ConfirmPayRequest {
- proposalId: string;
- sessionId?: string;
-}
-
-export const codecForConfirmPayRequest = (): Codec<ConfirmPayRequest> =>
- buildCodecForObject<ConfirmPayRequest>()
- .property("proposalId", codecForString())
- .property("sessionId", codecOptional(codecForString()))
- .build("ConfirmPay");
-
-/**
- * Implementation of the "wallet-core" API.
- */
-
-async function dispatchRequestInternal(
- wallet: Wallet,
- operation: string,
- payload: unknown,
-): Promise<Record<string, any>> {
- switch (operation) {
- case "withdrawTestkudos":
- await wallet.withdrawTestBalance();
- return {};
- case "getTransactions": {
- const req = codecForTransactionsRequest().decode(payload);
- return await wallet.getTransactions(req);
- }
- case "addExchange": {
- const req = codecForAddExchangeRequest().decode(payload);
- await wallet.updateExchangeFromUrl(req.exchangeBaseUrl);
- return {};
- }
- case "listExchanges": {
- return await wallet.getExchanges();
- }
- case "getWithdrawalDetailsForUri": {
- const req = codecForGetWithdrawalDetailsForUri().decode(payload);
- return await wallet.getWithdrawalDetailsForUri(req.talerWithdrawUri);
- }
- case "acceptManualWithdrawal": {
- const req = codecForAcceptManualWithdrawalRequet().decode(payload);
- const res = await wallet.acceptManualWithdrawal(
- req.exchangeBaseUrl,
- Amounts.parseOrThrow(req.amount),
- );
- return res;
- }
- case "getWithdrawalDetailsForAmount": {
- const req = codecForGetWithdrawalDetailsForAmountRequest().decode(
- payload,
- );
- return await wallet.getWithdrawalDetailsForAmount(
- req.exchangeBaseUrl,
- Amounts.parseOrThrow(req.amount),
- );
- }
- case "getBalances": {
- return await wallet.getBalances();
- }
- case "getPendingOperations": {
- return await wallet.getPendingOperations();
- }
- case "setExchangeTosAccepted": {
- const req = codecForAcceptExchangeTosRequest().decode(payload);
- await wallet.acceptExchangeTermsOfService(req.exchangeBaseUrl, req.etag);
- return {};
- }
- case "applyRefund": {
- const req = codecForApplyRefundRequest().decode(payload);
- return await wallet.applyRefund(req.talerRefundUri);
- }
- case "acceptBankIntegratedWithdrawal": {
- const req = codecForAcceptBankIntegratedWithdrawalRequest().decode(
- payload,
- );
- return await wallet.acceptWithdrawal(
- req.talerWithdrawUri,
- req.exchangeBaseUrl,
- );
- }
- case "getExchangeTos": {
- const req = codecForGetExchangeTosRequest().decode(payload);
- return wallet.getExchangeTos(req.exchangeBaseUrl);
- }
- case "abortProposal": {
- const req = codecForAbortProposalRequest().decode(payload);
- await wallet.refuseProposal(req.proposalId);
- return {};
- }
- case "retryPendingNow": {
- await wallet.runPending(true);
- return {};
- }
- case "preparePay": {
- const req = codecForPreparePayRequest().decode(payload);
- return await wallet.preparePayForUri(req.talerPayUri);
- }
- case "confirmPay": {
- const req = codecForConfirmPayRequest().decode(payload);
- return await wallet.confirmPay(req.proposalId, req.sessionId);
- }
- }
- throw OperationFailedError.fromCode(
- TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN,
- "unknown operation",
- {
- operation,
- },
- );
-}
-
-export type CoreApiResponse = CoreApiResponseSuccess | CoreApiResponseError;
-
-export type CoreApiEnvelope = CoreApiResponse | CoreApiNotification;
-
-export interface CoreApiNotification {
- type: "notification";
- payload: unknown;
-}
-
-export interface CoreApiResponseSuccess {
- // To distinguish the message from notifications
- type: "response";
- operation: string;
- id: string;
- result: unknown;
-}
-
-export interface CoreApiResponseError {
- // To distinguish the message from notifications
- type: "error";
- operation: string;
- id: string;
- error: OperationErrorDetails;
-}
-
-/**
- * Handle a request to the wallet-core API.
- */
-export async function handleCoreApiRequest(
- w: Wallet,
- operation: string,
- id: string,
- payload: unknown,
-): Promise<CoreApiResponse> {
- try {
- const result = await dispatchRequestInternal(w, operation, payload);
- return {
- type: "response",
- operation,
- id,
- result,
- };
- } catch (e) {
- if (
- e instanceof OperationFailedError ||
- e instanceof OperationFailedAndReportedError
- ) {
- return {
- type: "error",
- operation,
- id,
- error: e.operationError,
- };
- } else {
- return {
- type: "error",
- operation,
- id,
- error: makeErrorDetails(
- TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION,
- `unexpected exception: ${e}`,
- {},
- ),
- };
- }
- }
-}
diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts
index 86008dd99..60d0b6d49 100644
--- a/packages/taler-wallet-webextension/src/wxBackend.ts
+++ b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -24,7 +24,6 @@
* Imports.
*/
import { isFirefox, getPermissionsApi } from "./compat";
-import * as wxApi from "./wxApi";
import MessageSender = chrome.runtime.MessageSender;
import { extendedPermissions } from "./permissions";
@@ -32,16 +31,12 @@ import {
Wallet,
OpenedPromise,
openPromise,
- deleteTalerDatabase,
- WALLET_DB_MINOR_VERSION,
- WalletDiagnostics,
openTalerDatabase,
Database,
classifyTalerUri,
TalerUriType,
makeErrorDetails,
TalerErrorCode,
- handleCoreApiRequest,
} from "taler-wallet-core";
import { BrowserHttpLib } from "./browserHttpLib";
import { BrowserCryptoWorkerFactory } from "./browserCryptoWorkerFactory";
@@ -82,7 +77,7 @@ async function dispatch(
return;
}
- const r = await handleCoreApiRequest(w, req.operation, req.id, req.payload);
+ const r = await w.handleCoreApiRequest(req.operation, req.id, req.payload);
try {
sendResponse(r);
} catch (e) {
@@ -251,7 +246,7 @@ function headerListener(
);
case TalerUriType.TalerRefund:
return makeSyncWalletRedirect(
- "/static/refund.html",
+ "refund.html",
details.tabId,
details.url,
{
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 78011a19e..9bdba271c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -83,6 +83,7 @@ importers:
typescript: ^3.9.7
packages/taler-wallet-cli:
dependencies:
+ axios: 0.19.2
source-map-support: 0.5.19
taler-wallet-core: 'link:../taler-wallet-core'
tslib: 2.0.1
@@ -105,6 +106,7 @@ importers:
'@rollup/plugin-node-resolve': ^8.4.0
'@rollup/plugin-replace': ^2.3.3
'@types/node': ^14.0.27
+ axios: ^0.19.2
prettier: ^2.0.5
rimraf: ^3.0.2
rollup: ^2.23.0