re-implement integration test functionalty that will be used by the exchange for testing
This commit is contained in:
parent
d5f894690e
commit
e3850158c2
@ -38,7 +38,6 @@ import {
|
|||||||
WalletNotification,
|
WalletNotification,
|
||||||
WALLET_EXCHANGE_PROTOCOL_VERSION,
|
WALLET_EXCHANGE_PROTOCOL_VERSION,
|
||||||
WALLET_MERCHANT_PROTOCOL_VERSION,
|
WALLET_MERCHANT_PROTOCOL_VERSION,
|
||||||
handleCoreApiRequest,
|
|
||||||
} from "taler-wallet-core";
|
} from "taler-wallet-core";
|
||||||
|
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
@ -229,7 +228,7 @@ class AndroidWalletMessageHandler {
|
|||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
const wallet = await this.wp.promise;
|
const wallet = await this.wp.promise;
|
||||||
return await handleCoreApiRequest(wallet, operation, id, args);
|
return await wallet.handleCoreApiRequest(operation, id, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
"typescript": "^3.9.7"
|
"typescript": "^3.9.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"axios": "^0.19.2",
|
||||||
"source-map-support": "^0.5.19",
|
"source-map-support": "^0.5.19",
|
||||||
"taler-wallet-core": "workspace:*",
|
"taler-wallet-core": "workspace:*",
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
|
@ -26,7 +26,6 @@ import {
|
|||||||
NodeHttpLib,
|
NodeHttpLib,
|
||||||
PreparePayResultType,
|
PreparePayResultType,
|
||||||
setDangerousTimetravel,
|
setDangerousTimetravel,
|
||||||
handleCoreApiRequest,
|
|
||||||
classifyTalerUri,
|
classifyTalerUri,
|
||||||
TalerUriType,
|
TalerUriType,
|
||||||
decodeCrock,
|
decodeCrock,
|
||||||
@ -34,10 +33,10 @@ import {
|
|||||||
codecForList,
|
codecForList,
|
||||||
codecForString,
|
codecForString,
|
||||||
printTestVectors,
|
printTestVectors,
|
||||||
|
NodeThreadCryptoWorkerFactory,
|
||||||
|
CryptoApi,
|
||||||
} from "taler-wallet-core";
|
} from "taler-wallet-core";
|
||||||
import * as clk from "./clk";
|
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
|
// This module also serves as the entry point for the crypto
|
||||||
// thread worker, and thus must expose these two handlers.
|
// thread worker, and thus must expose these two handlers.
|
||||||
@ -210,8 +209,7 @@ walletCli
|
|||||||
console.error("Invalid JSON");
|
console.error("Invalid JSON");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
const resp = await handleCoreApiRequest(
|
const resp = await wallet.handleCoreApiRequest(
|
||||||
wallet,
|
|
||||||
args.api.operation,
|
args.api.operation,
|
||||||
"reqid-1",
|
"reqid-1",
|
||||||
requestJson,
|
requestJson,
|
||||||
|
@ -37,8 +37,6 @@ export * from "./types/walletTypes";
|
|||||||
|
|
||||||
export * from "./types/talerTypes";
|
export * from "./types/talerTypes";
|
||||||
|
|
||||||
export * from "./walletCoreApiHandler";
|
|
||||||
|
|
||||||
export * from "./util/taleruri";
|
export * from "./util/taleruri";
|
||||||
|
|
||||||
export * from "./util/time";
|
export * from "./util/time";
|
||||||
@ -54,7 +52,7 @@ export * from "./util/testvectors";
|
|||||||
export * from "./operations/versions";
|
export * from "./operations/versions";
|
||||||
|
|
||||||
export type { CryptoWorker } from "./crypto/workers/cryptoWorker";
|
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";
|
export * from "./util/http";
|
||||||
|
|
||||||
|
@ -21,10 +21,19 @@ import {
|
|||||||
checkSuccessResponseOrThrow,
|
checkSuccessResponseOrThrow,
|
||||||
} from "../util/http";
|
} from "../util/http";
|
||||||
import { codecForAny } from "../util/codec";
|
import { codecForAny } from "../util/codec";
|
||||||
import { AmountString } from "../types/talerTypes";
|
import {
|
||||||
|
AmountString,
|
||||||
|
CheckPaymentResponse,
|
||||||
|
codecForCheckPaymentResponse,
|
||||||
|
} from "../types/talerTypes";
|
||||||
import { InternalWalletState } from "./state";
|
import { InternalWalletState } from "./state";
|
||||||
import { createTalerWithdrawReserve } from "./reserves";
|
import { createTalerWithdrawReserve } from "./reserves";
|
||||||
import { URL } from "../util/url";
|
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");
|
const logger = new Logger("operations/testing.ts");
|
||||||
|
|
||||||
@ -38,6 +47,11 @@ interface BankWithdrawalResponse {
|
|||||||
withdrawal_id: string;
|
withdrawal_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface MerchantBackendInfo {
|
||||||
|
baseUrl: string;
|
||||||
|
apikey: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a random alphanumeric ID. Does *not* use cryptographically
|
* Generate a random alphanumeric ID. Does *not* use cryptographically
|
||||||
* secure randomness.
|
* secure randomness.
|
||||||
@ -154,3 +168,268 @@ async function registerRandomBankUser(
|
|||||||
await checkSuccessResponseOrThrow(resp);
|
await checkSuccessResponseOrThrow(resp);
|
||||||
return bankUser;
|
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);
|
||||||
|
}
|
||||||
|
@ -229,9 +229,7 @@ export const codecForConfirmPayResultPending = (): Codec<
|
|||||||
.property("type", codecForConstString(ConfirmPayResultType.Pending))
|
.property("type", codecForConstString(ConfirmPayResultType.Pending))
|
||||||
.build("ConfirmPayResultPending");
|
.build("ConfirmPayResultPending");
|
||||||
|
|
||||||
export const codecForConfirmPayResultDone = (): Codec<
|
export const codecForConfirmPayResultDone = (): Codec<ConfirmPayResultDone> =>
|
||||||
ConfirmPayResultDone
|
|
||||||
> =>
|
|
||||||
buildCodecForObject<ConfirmPayResultDone>()
|
buildCodecForObject<ConfirmPayResultDone>()
|
||||||
.property("type", codecForConstString(ConfirmPayResultType.Done))
|
.property("type", codecForConstString(ConfirmPayResultType.Done))
|
||||||
.property("nextUrl", codecForString())
|
.property("nextUrl", codecForString())
|
||||||
@ -240,7 +238,10 @@ export const codecForConfirmPayResultDone = (): Codec<
|
|||||||
export const codecForConfirmPayResult = (): Codec<ConfirmPayResult> =>
|
export const codecForConfirmPayResult = (): Codec<ConfirmPayResult> =>
|
||||||
buildCodecForUnion<ConfirmPayResult>()
|
buildCodecForUnion<ConfirmPayResult>()
|
||||||
.discriminateOn("type")
|
.discriminateOn("type")
|
||||||
.alternative(ConfirmPayResultType.Pending, codecForConfirmPayResultPending())
|
.alternative(
|
||||||
|
ConfirmPayResultType.Pending,
|
||||||
|
codecForConfirmPayResultPending(),
|
||||||
|
)
|
||||||
.alternative(ConfirmPayResultType.Done, codecForConfirmPayResultDone())
|
.alternative(ConfirmPayResultType.Done, codecForConfirmPayResultDone())
|
||||||
.build("ConfirmPayResult");
|
.build("ConfirmPayResult");
|
||||||
|
|
||||||
@ -650,3 +651,181 @@ export interface GetExchangeTosResult {
|
|||||||
*/
|
*/
|
||||||
acceptedEtag: string | undefined;
|
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;
|
||||||
|
}
|
||||||
|
@ -70,6 +70,22 @@ import {
|
|||||||
GetExchangeTosResult,
|
GetExchangeTosResult,
|
||||||
AcceptManualWithdrawalResult,
|
AcceptManualWithdrawalResult,
|
||||||
BalancesResponse,
|
BalancesResponse,
|
||||||
|
TestPayArgs,
|
||||||
|
PreparePayResultType,
|
||||||
|
IntegrationTestArgs,
|
||||||
|
codecForAddExchangeRequest,
|
||||||
|
codecForGetWithdrawalDetailsForUri,
|
||||||
|
codecForAcceptManualWithdrawalRequet,
|
||||||
|
codecForGetWithdrawalDetailsForAmountRequest,
|
||||||
|
codecForAcceptExchangeTosRequest,
|
||||||
|
codecForApplyRefundRequest,
|
||||||
|
codecForAcceptBankIntegratedWithdrawalRequest,
|
||||||
|
codecForGetExchangeTosRequest,
|
||||||
|
codecForAbortProposalRequest,
|
||||||
|
codecForConfirmPayRequest,
|
||||||
|
CoreApiResponse,
|
||||||
|
codecForPreparePayRequest,
|
||||||
|
codecForIntegrationTestArgs,
|
||||||
} from "./types/walletTypes";
|
} from "./types/walletTypes";
|
||||||
import { Logger } from "./util/logging";
|
import { Logger } from "./util/logging";
|
||||||
|
|
||||||
@ -107,13 +123,23 @@ import { WalletNotification, NotificationType } from "./types/notifications";
|
|||||||
import { processPurchaseQueryRefund, applyRefund } from "./operations/refund";
|
import { processPurchaseQueryRefund, applyRefund } from "./operations/refund";
|
||||||
import { durationMin, Duration } from "./util/time";
|
import { durationMin, Duration } from "./util/time";
|
||||||
import { processRecoupGroup } from "./operations/recoup";
|
import { processRecoupGroup } from "./operations/recoup";
|
||||||
import { OperationFailedAndReportedError } from "./operations/errors";
|
import {
|
||||||
|
OperationFailedAndReportedError,
|
||||||
|
OperationFailedError,
|
||||||
|
makeErrorDetails,
|
||||||
|
} from "./operations/errors";
|
||||||
import {
|
import {
|
||||||
TransactionsRequest,
|
TransactionsRequest,
|
||||||
TransactionsResponse,
|
TransactionsResponse,
|
||||||
|
codecForTransactionsRequest,
|
||||||
} from "./types/transactions";
|
} from "./types/transactions";
|
||||||
import { getTransactions } from "./operations/transactions";
|
import { getTransactions } from "./operations/transactions";
|
||||||
import { withdrawTestBalance } from "./operations/testing";
|
import {
|
||||||
|
withdrawTestBalance,
|
||||||
|
runIntegrationTest,
|
||||||
|
testPay,
|
||||||
|
} from "./operations/testing";
|
||||||
|
import { TalerErrorCode } from ".";
|
||||||
|
|
||||||
const builtinCurrencies: CurrencyRecord[] = [
|
const builtinCurrencies: CurrencyRecord[] = [
|
||||||
{
|
{
|
||||||
@ -879,4 +905,168 @@ export class Wallet {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await withdrawTestBalance(this.ws, amount, bankBaseUrl, exchangeBaseUrl);
|
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}`,
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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}`,
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,7 +24,6 @@
|
|||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import { isFirefox, getPermissionsApi } from "./compat";
|
import { isFirefox, getPermissionsApi } from "./compat";
|
||||||
import * as wxApi from "./wxApi";
|
|
||||||
import MessageSender = chrome.runtime.MessageSender;
|
import MessageSender = chrome.runtime.MessageSender;
|
||||||
import { extendedPermissions } from "./permissions";
|
import { extendedPermissions } from "./permissions";
|
||||||
|
|
||||||
@ -32,16 +31,12 @@ import {
|
|||||||
Wallet,
|
Wallet,
|
||||||
OpenedPromise,
|
OpenedPromise,
|
||||||
openPromise,
|
openPromise,
|
||||||
deleteTalerDatabase,
|
|
||||||
WALLET_DB_MINOR_VERSION,
|
|
||||||
WalletDiagnostics,
|
|
||||||
openTalerDatabase,
|
openTalerDatabase,
|
||||||
Database,
|
Database,
|
||||||
classifyTalerUri,
|
classifyTalerUri,
|
||||||
TalerUriType,
|
TalerUriType,
|
||||||
makeErrorDetails,
|
makeErrorDetails,
|
||||||
TalerErrorCode,
|
TalerErrorCode,
|
||||||
handleCoreApiRequest,
|
|
||||||
} from "taler-wallet-core";
|
} from "taler-wallet-core";
|
||||||
import { BrowserHttpLib } from "./browserHttpLib";
|
import { BrowserHttpLib } from "./browserHttpLib";
|
||||||
import { BrowserCryptoWorkerFactory } from "./browserCryptoWorkerFactory";
|
import { BrowserCryptoWorkerFactory } from "./browserCryptoWorkerFactory";
|
||||||
@ -82,7 +77,7 @@ async function dispatch(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const r = await handleCoreApiRequest(w, req.operation, req.id, req.payload);
|
const r = await w.handleCoreApiRequest(req.operation, req.id, req.payload);
|
||||||
try {
|
try {
|
||||||
sendResponse(r);
|
sendResponse(r);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -251,7 +246,7 @@ function headerListener(
|
|||||||
);
|
);
|
||||||
case TalerUriType.TalerRefund:
|
case TalerUriType.TalerRefund:
|
||||||
return makeSyncWalletRedirect(
|
return makeSyncWalletRedirect(
|
||||||
"/static/refund.html",
|
"refund.html",
|
||||||
details.tabId,
|
details.tabId,
|
||||||
details.url,
|
details.url,
|
||||||
{
|
{
|
||||||
|
@ -83,6 +83,7 @@ importers:
|
|||||||
typescript: ^3.9.7
|
typescript: ^3.9.7
|
||||||
packages/taler-wallet-cli:
|
packages/taler-wallet-cli:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
axios: 0.19.2
|
||||||
source-map-support: 0.5.19
|
source-map-support: 0.5.19
|
||||||
taler-wallet-core: 'link:../taler-wallet-core'
|
taler-wallet-core: 'link:../taler-wallet-core'
|
||||||
tslib: 2.0.1
|
tslib: 2.0.1
|
||||||
@ -105,6 +106,7 @@ importers:
|
|||||||
'@rollup/plugin-node-resolve': ^8.4.0
|
'@rollup/plugin-node-resolve': ^8.4.0
|
||||||
'@rollup/plugin-replace': ^2.3.3
|
'@rollup/plugin-replace': ^2.3.3
|
||||||
'@types/node': ^14.0.27
|
'@types/node': ^14.0.27
|
||||||
|
axios: ^0.19.2
|
||||||
prettier: ^2.0.5
|
prettier: ^2.0.5
|
||||||
rimraf: ^3.0.2
|
rimraf: ^3.0.2
|
||||||
rollup: ^2.23.0
|
rollup: ^2.23.0
|
||||||
|
Loading…
Reference in New Issue
Block a user