aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-harness/src/harness
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-harness/src/harness')
-rw-r--r--packages/taler-harness/src/harness/harness.ts181
-rw-r--r--packages/taler-harness/src/harness/helpers.ts22
-rw-r--r--packages/taler-harness/src/harness/libeufin-apis.ts775
-rw-r--r--packages/taler-harness/src/harness/libeufin.ts1047
4 files changed, 171 insertions, 1854 deletions
diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts
index 0c3c367af..e30cbcb54 100644
--- a/packages/taler-harness/src/harness/harness.ts
+++ b/packages/taler-harness/src/harness/harness.ts
@@ -28,7 +28,7 @@ import {
AccountAddDetails,
AmountJson,
Amounts,
- BankAccessApiClient,
+ TalerCorebankApiClient,
Configuration,
CoreApiResponse,
Duration,
@@ -565,7 +565,7 @@ class BankServiceBase {
protected globalTestState: GlobalTestState,
protected bankConfig: BankConfig,
protected configFile: string,
- ) { }
+ ) {}
}
export interface HarnessExchangeBankAccount {
@@ -580,7 +580,8 @@ export interface HarnessExchangeBankAccount {
*/
export class FakebankService
extends BankServiceBase
- implements BankServiceHandle {
+ implements BankServiceHandle
+{
proc: ProcessWrapper | undefined;
http = createPlatformHttpLib({ enableThrottling: false });
@@ -649,9 +650,8 @@ export class FakebankService
return `http://localhost:${this.bankConfig.httpPort}/`;
}
- get bankAccessApiBaseUrl(): string {
- let url = new URL("taler-bank-access/", this.baseUrl);
- return url.href;
+ get corebankApiBaseUrl(): string {
+ return this.baseUrl;
}
async createExchangeAccount(
@@ -665,8 +665,8 @@ export class FakebankService
return {
accountName: accountName,
accountPassword: password,
- accountPaytoUri: getPayto(accountName),
- wireGatewayApiBaseUrl: `http://localhost:${this.bankConfig.httpPort}/taler-wire-gateway/${accountName}/`,
+ accountPaytoUri: generateRandomPayto(accountName),
+ wireGatewayApiBaseUrl: `http://localhost:${this.bankConfig.httpPort}/accounts/${accountName}/taler-wire-gateway/`,
};
}
@@ -691,23 +691,157 @@ export class FakebankService
"bank",
);
await this.pingUntilAvailable();
- const bankClient = new BankAccessApiClient(this.bankAccessApiBaseUrl);
+ const bankClient = new TalerCorebankApiClient(this.corebankApiBaseUrl);
for (const acc of this.accounts) {
await bankClient.registerAccount(acc.accountName, acc.accountPassword);
}
}
async pingUntilAvailable(): Promise<void> {
- const url = `http://localhost:${this.bankConfig.httpPort}/taler-bank-integration/config`;
+ const url = `http://localhost:${this.bankConfig.httpPort}/config`;
await pingProc(this.proc, url, "bank");
}
}
+/**
+ * Implementation of the bank service using the "taler-fakebank-run" tool.
+ */
+export class LibeufinBankService
+ extends BankServiceBase
+ implements BankServiceHandle
+{
+ proc: ProcessWrapper | undefined;
+
+ http = createPlatformHttpLib({ enableThrottling: false });
+
+ // We store "created" accounts during setup and
+ // register them after startup.
+ private accounts: {
+ accountName: string;
+ accountPassword: string;
+ }[] = [];
+
+ /**
+ * Create a new fakebank service handle.
+ *
+ * First generates the configuration for the fakebank and
+ * then creates a fakebank handle, but doesn't start the fakebank
+ * service yet.
+ */
+ static async create(
+ gc: GlobalTestState,
+ bc: BankConfig,
+ ): Promise<LibeufinBankService> {
+ const config = new Configuration();
+ const testDir = bc.overrideTestDir ?? gc.testDir;
+ setTalerPaths(config, testDir + "/talerhome");
+ config.setString("libeufin-bankdb-postgres", "config", bc.database);
+ config.setString("libeufin-bank", "currency", bc.currency);
+ config.setString("libeufin-bank", "port", `${bc.httpPort}`);
+ config.setString("libeufin-bank", "serve", "tcp");
+ config.setString(
+ "libeufin-bank",
+ "DEFAULT_CUSTOMER_DEBT_LIMIT",
+ `${bc.currency}:500`,
+ );
+ config.setString(
+ "libeufin-bank",
+ "DEFAULT_ADMIN_DEBT_LIMIT",
+ `${bc.currency}:999999`,
+ );
+ config.setString(
+ "libeufin-bank",
+ "registration_bonus",
+ `${bc.currency}:100`,
+ );
+ config.setString("libeufin-bank", "registration_bonus_enabled", `yes`);
+ config.setString("libeufin-bank", "max_auth_token_duration", "1h");
+ const cfgFilename = testDir + "/bank.conf";
+ config.write(cfgFilename, { excludeDefaults: true });
+
+ return new LibeufinBankService(gc, bc, cfgFilename);
+ }
+
+ static fromExistingConfig(
+ gc: GlobalTestState,
+ opts: { overridePath?: string },
+ ): FakebankService {
+ const testDir = opts.overridePath ?? gc.testDir;
+ const cfgFilename = testDir + `/bank.conf`;
+ const config = Configuration.load(cfgFilename);
+ const bc: BankConfig = {
+ allowRegistrations:
+ config.getYesNo("libeufin-bank", "allow_registrations").orUndefined() ??
+ true,
+ currency: config.getString("libeufin-bank", "currency").required(),
+ database: config
+ .getString("libeufin-bankdb-postgres", "config")
+ .required(),
+ httpPort: config.getNumber("libeufin-bank", "port").required(),
+ maxDebt: config
+ .getString("libeufin-bank", "DEFAULT_CUSTOMER_DEBT_LIMIT")
+ .required(),
+ };
+ return new FakebankService(gc, bc, cfgFilename);
+ }
+
+ setSuggestedExchange(e: ExchangeServiceInterface) {
+ if (!!this.proc) {
+ throw Error("Can't set suggested exchange while bank is running.");
+ }
+ const config = Configuration.load(this.configFile);
+ config.setString("libeufin-bank", "suggested_withdrawal_exchange", e.baseUrl);
+ config.write(this.configFile, { excludeDefaults: true });
+ }
+
+ get baseUrl(): string {
+ return `http://localhost:${this.bankConfig.httpPort}/`;
+ }
+
+ get corebankApiBaseUrl(): string {
+ return this.baseUrl;
+ }
+
+ get port() {
+ return this.bankConfig.httpPort;
+ }
+
+ async start(): Promise<void> {
+ logger.info("starting libeufin-bank");
+ if (this.proc) {
+ logger.info("libeufin-bank already running, not starting again");
+ return;
+ }
+
+ await sh(
+ this.globalTestState,
+ "libeufin-bank-dbinit",
+ `libeufin-bank dbinit -r -c "${this.configFile}"`,
+ );
+
+ this.proc = this.globalTestState.spawnService(
+ "libeufin-bank",
+ ["serve", "-c", this.configFile],
+ "libeufin-bank-httpd",
+ );
+ await this.pingUntilAvailable();
+ const bankClient = new TalerCorebankApiClient(this.corebankApiBaseUrl);
+ for (const acc of this.accounts) {
+ await bankClient.registerAccount(acc.accountName, acc.accountPassword);
+ }
+ }
+
+ async pingUntilAvailable(): Promise<void> {
+ const url = `http://localhost:${this.bankConfig.httpPort}/config`;
+ await pingProc(this.proc, url, "libeufin-bank");
+ }
+}
+
// Use libeufin bank instead of pybank.
const useLibeufinBank = false;
export interface BankServiceHandle {
- readonly bankAccessApiBaseUrl: string;
+ readonly corebankApiBaseUrl: string;
readonly http: HttpRequestLibrary;
}
@@ -1012,7 +1146,7 @@ export class ExchangeService implements ExchangeServiceInterface {
private exchangeConfig: ExchangeConfig,
private configFilename: string,
private keyPair: EddsaKeyPair,
- ) { }
+ ) {}
get name() {
return this.exchangeConfig.name;
@@ -1368,7 +1502,7 @@ export class MerchantService implements MerchantServiceInterface {
private globalState: GlobalTestState,
private merchantConfig: MerchantConfig,
private configFilename: string,
- ) { }
+ ) {}
private currentTimetravelOffsetMs: number | undefined;
@@ -1496,7 +1630,7 @@ export class MerchantService implements MerchantServiceInterface {
return await this.addInstanceWithWireAccount({
id: "default",
name: "Default Instance",
- paytoUris: [getPayto("merchant-default")],
+ paytoUris: [generateRandomPayto("merchant-default")],
auth: {
method: "external",
},
@@ -1659,6 +1793,7 @@ export async function runTestWithState(
e.message,
`error detail: ${j2s(e.errorDetail)}`,
);
+ console.error(e.stack);
} else {
console.error("FATAL: test failed with exception", e);
}
@@ -1706,7 +1841,7 @@ export class WalletService {
constructor(
private globalState: GlobalTestState,
private opts: WalletServiceOptions,
- ) { }
+ ) {}
get socketPath() {
const unixPath = path.join(
@@ -1815,7 +1950,7 @@ export class WalletClient {
return client.call(operation, payload);
}
- constructor(private args: WalletClientArgs) { }
+ constructor(private args: WalletClientArgs) {}
async connect(): Promise<void> {
const waiter = this.waiter;
@@ -1882,9 +2017,11 @@ export class WalletCli {
? `--crypto-worker=${cliOpts.cryptoWorkerType}`
: "";
const logName = `wallet-${self.name}`;
- const command = `taler-wallet-cli ${self.timetravelArg ?? ""
- } ${cryptoWorkerArg} --no-throttle -LTRACE --skip-defaults --wallet-db '${self.dbfile
- }' api '${op}' ${shellWrap(JSON.stringify(payload))}`;
+ const command = `taler-wallet-cli ${
+ self.timetravelArg ?? ""
+ } ${cryptoWorkerArg} --no-throttle -LTRACE --skip-defaults --wallet-db '${
+ self.dbfile
+ }' api '${op}' ${shellWrap(JSON.stringify(payload))}`;
const resp = await sh(self.globalTestState, logName, command);
logger.info("--- wallet core response ---");
logger.info(resp);
@@ -1967,7 +2104,7 @@ export class WalletCli {
}
}
-export function getRandomIban(salt: string | null = null): string {
+export function generateRandomTestIban(salt: string | null = null): string {
function getBban(salt: string | null): string {
if (!salt) return Math.random().toString().substring(2, 6);
let hashed = hash(stringToBytes(salt));
@@ -1999,9 +2136,9 @@ export function getWireMethodForTest(): string {
* Generate a payto address, whose authority depends
* on whether the banking is served by euFin or Pybank.
*/
-export function getPayto(label: string): string {
+export function generateRandomPayto(label: string): string {
if (useLibeufinBank)
- return `payto://iban/SANDBOXX/${getRandomIban(
+ return `payto://iban/SANDBOXX/${generateRandomTestIban(
label,
)}?receiver-name=${label}`;
return `payto://x-taler-bank/localhost/${label}`;
diff --git a/packages/taler-harness/src/harness/helpers.ts b/packages/taler-harness/src/harness/helpers.ts
index 9892e600b..8c1612457 100644
--- a/packages/taler-harness/src/harness/helpers.ts
+++ b/packages/taler-harness/src/harness/helpers.ts
@@ -25,7 +25,7 @@
*/
import {
AmountString,
- BankAccessApiClient,
+ TalerCorebankApiClient,
ConfirmPayResultType,
Duration,
Logger,
@@ -56,7 +56,7 @@ import {
WalletClient,
WalletService,
WithAuthorization,
- getPayto,
+ generateRandomPayto,
setupDb,
setupSharedDb,
} from "./harness.js";
@@ -236,7 +236,7 @@ export async function useSharedTestkudosEnvironment(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({
id: "default",
name: "Default Instance",
- paytoUris: [getPayto("merchant-default")],
+ paytoUris: [generateRandomPayto("merchant-default")],
defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }),
),
@@ -245,7 +245,7 @@ export async function useSharedTestkudosEnvironment(t: GlobalTestState) {
await merchant.addInstanceWithWireAccount({
id: "minst1",
name: "minst1",
- paytoUris: [getPayto("minst1")],
+ paytoUris: [generateRandomPayto("minst1")],
defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }),
),
@@ -368,7 +368,7 @@ export async function createSimpleTestkudosEnvironmentV2(
await merchant.addInstanceWithWireAccount({
id: "default",
name: "Default Instance",
- paytoUris: [getPayto("merchant-default")],
+ paytoUris: [generateRandomPayto("merchant-default")],
defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }),
),
@@ -377,7 +377,7 @@ export async function createSimpleTestkudosEnvironmentV2(
await merchant.addInstanceWithWireAccount({
id: "minst1",
name: "minst1",
- paytoUris: [getPayto("minst1")],
+ paytoUris: [generateRandomPayto("minst1")],
defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ minutes: 1 }),
),
@@ -512,13 +512,13 @@ export async function createFaultInjectedMerchantTestkudosEnvironment(
await merchant.addInstanceWithWireAccount({
id: "default",
name: "Default Instance",
- paytoUris: [getPayto("merchant-default")],
+ paytoUris: [generateRandomPayto("merchant-default")],
});
await merchant.addInstanceWithWireAccount({
id: "minst1",
name: "minst1",
- paytoUris: [getPayto("minst1")],
+ paytoUris: [generateRandomPayto("minst1")],
});
console.log("setup done!");
@@ -560,7 +560,7 @@ export async function withdrawViaBankV2(
): Promise<WithdrawViaBankResult> {
const { walletClient: wallet, bank, exchange, amount } = p;
- const bankClient = new BankAccessApiClient(bank.bankAccessApiBaseUrl);
+ const bankClient = new TalerCorebankApiClient(bank.corebankApiBaseUrl);
const user = await bankClient.createRandomBankUser();
const wop = await bankClient.createWithdrawalOperation(user.username, amount);
@@ -592,7 +592,9 @@ export async function withdrawViaBankV2(
// Confirm it
- await bankClient.confirmWithdrawalOperation(user.username, wop);
+ await bankClient.confirmWithdrawalOperation(user.username, {
+ withdrawalOperationId: wop.withdrawal_id,
+ });
return {
withdrawalFinishedCond,
diff --git a/packages/taler-harness/src/harness/libeufin-apis.ts b/packages/taler-harness/src/harness/libeufin-apis.ts
deleted file mode 100644
index 0193f9252..000000000
--- a/packages/taler-harness/src/harness/libeufin-apis.ts
+++ /dev/null
@@ -1,775 +0,0 @@
-/**
- * This file defines most of the API calls offered
- * by Nexus and Sandbox. They don't have state,
- * therefore got moved away from libeufin.ts where
- * the services get actually started and managed.
- */
-
-import { URL } from "@gnu-taler/taler-util";
-import {
- createPlatformHttpLib,
- makeBasicAuthHeader,
-} from "@gnu-taler/taler-util/http";
-import {
- LibeufinNexusTransactions,
- LibeufinSandboxAdminBankAccountBalance,
- NexusBankConnections,
- NexusFacadeListResponse,
- NexusGetPermissionsResponse,
- NexusNewTransactionsInfo,
- NexusTask,
- NexusTaskCollection,
- NexusUserResponse,
-} from "./libeufin.js";
-
-export interface LibeufinSandboxServiceInterface {
- baseUrl: string;
-}
-
-export interface LibeufinNexusServiceInterface {
- baseUrl: string;
-}
-
-export interface CreateEbicsSubscriberRequest {
- hostID: string;
- userID: string;
- partnerID: string;
- systemID?: string;
-}
-
-export interface BankAccountInfo {
- iban: string;
- bic: string;
- name: string;
- label: string;
-}
-
-export interface CreateEbicsBankConnectionRequest {
- name: string; // connection name.
- ebicsURL: string;
- hostID: string;
- userID: string;
- partnerID: string;
- systemID?: string;
-}
-
-export interface UpdateNexusUserRequest {
- newPassword: string;
-}
-
-export interface NexusAuth {
- auth: {
- username: string;
- password: string;
- };
-}
-
-export interface PostNexusTaskRequest {
- name: string;
- cronspec: string;
- type: string; // fetch | submit
- params:
- | {
- level: string; // report | statement | all
- rangeType: string; // all | since-last | previous-days | latest
- }
- | {};
-}
-
-export interface CreateNexusUserRequest {
- username: string;
- password: string;
-}
-
-export interface PostNexusPermissionRequest {
- action: "revoke" | "grant";
- permission: {
- subjectType: string;
- subjectId: string;
- resourceType: string;
- resourceId: string;
- permissionName: string;
- };
-}
-
-export interface CreateAnastasisFacadeRequest {
- name: string;
- connectionName: string;
- accountName: string;
- currency: string;
- reserveTransferLevel: "report" | "statement" | "notification";
-}
-
-export interface CreateTalerWireGatewayFacadeRequest {
- name: string;
- connectionName: string;
- accountName: string;
- currency: string;
- reserveTransferLevel: "report" | "statement" | "notification";
-}
-
-export interface SandboxAccountTransactions {
- payments: {
- accountLabel: string;
- creditorIban: string;
- creditorBic?: string;
- creditorName: string;
- debtorIban: string;
- debtorBic: string;
- debtorName: string;
- amount: string;
- currency: string;
- subject: string;
- date: string;
- creditDebitIndicator: "debit" | "credit";
- accountServicerReference: string;
- }[];
-}
-
-export interface DeleteBankConnectionRequest {
- bankConnectionId: string;
-}
-
-export interface SimulateIncomingTransactionRequest {
- debtorIban: string;
- debtorBic: string;
- debtorName: string;
-
- /**
- * Subject / unstructured remittance info.
- */
- subject: string;
-
- /**
- * Decimal amount without currency.
- */
- amount: string;
-}
-
-export interface CreateEbicsBankAccountRequest {
- subscriber: {
- hostID: string;
- partnerID: string;
- userID: string;
- systemID?: string;
- };
- // IBAN
- iban: string;
- // BIC
- bic: string;
- // human name
- name: string;
- label: string;
-}
-
-export interface LibeufinSandboxAddIncomingRequest {
- creditorIban: string;
- creditorBic: string;
- creditorName: string;
- debtorIban: string;
- debtorBic: string;
- debtorName: string;
- subject: string;
- amount: string;
- currency: string;
- uid: string;
- direction: string;
-}
-
-const libeufinHarnessHttpLib = createPlatformHttpLib();
-
-/**
- * APIs spread across Legacy and Access, it is therefore
- * the "base URL" relative to which API every call addresses.
- */
-export namespace LibeufinSandboxApi {
- // Creates one bank account via the Access API.
- // Need the /demobanks/$id/access-api as the base URL
- export async function createDemobankAccount(
- username: string,
- password: string,
- libeufinSandboxService: LibeufinSandboxServiceInterface,
- iban: string | null = null,
- ): Promise<void> {
- let url = new URL("testing/register", libeufinSandboxService.baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- body: {
- username: username,
- password: password,
- iban: iban,
- },
- });
- }
- // Need /demobanks/$id as the base URL
- export async function createDemobankEbicsSubscriber(
- req: CreateEbicsSubscriberRequest,
- demobankAccountLabel: string,
- libeufinSandboxService: LibeufinSandboxServiceInterface,
- username: string = "admin",
- password: string = "secret",
- ): Promise<void> {
- // baseUrl should already be pointed to one demobank.
- let url = new URL("ebics/subscribers", libeufinSandboxService.baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- body: {
- userID: req.userID,
- hostID: req.hostID,
- partnerID: req.partnerID,
- demobankAccountLabel: demobankAccountLabel,
- },
- });
- }
-
- export async function rotateKeys(
- libeufinSandboxService: LibeufinSandboxServiceInterface,
- hostID: string,
- ): Promise<void> {
- const baseUrl = libeufinSandboxService.baseUrl;
- let url = new URL(`admin/ebics/hosts/${hostID}/rotate-keys`, baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- body: {},
- });
- }
- export async function createEbicsHost(
- libeufinSandboxService: LibeufinSandboxServiceInterface,
- hostID: string,
- ): Promise<void> {
- const baseUrl = libeufinSandboxService.baseUrl;
- let url = new URL("admin/ebics/hosts", baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- body: {
- hostID,
- ebicsVersion: "2.5",
- },
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- }
-
- export async function createBankAccount(
- libeufinSandboxService: LibeufinSandboxServiceInterface,
- req: BankAccountInfo,
- ): Promise<void> {
- const baseUrl = libeufinSandboxService.baseUrl;
- let url = new URL(`admin/bank-accounts/${req.label}`, baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- body: req,
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- }
-
- /**
- * This function is useless. It creates a Ebics subscriber
- * but never gives it a bank account. To be removed
- */
- export async function createEbicsSubscriber(
- libeufinSandboxService: LibeufinSandboxServiceInterface,
- req: CreateEbicsSubscriberRequest,
- ): Promise<void> {
- const baseUrl = libeufinSandboxService.baseUrl;
- let url = new URL("admin/ebics/subscribers", baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- body: req,
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- }
-
- /**
- * Create a new bank account and associate it to
- * a existing EBICS subscriber.
- */
- export async function createEbicsBankAccount(
- libeufinSandboxService: LibeufinSandboxServiceInterface,
- req: CreateEbicsBankAccountRequest,
- ): Promise<void> {
- const baseUrl = libeufinSandboxService.baseUrl;
- let url = new URL("admin/ebics/bank-accounts", baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- body: req,
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- }
-
- export async function simulateIncomingTransaction(
- libeufinSandboxService: LibeufinSandboxServiceInterface,
- accountLabel: string,
- req: SimulateIncomingTransactionRequest,
- ): Promise<void> {
- const baseUrl = libeufinSandboxService.baseUrl;
- let url = new URL(
- `admin/bank-accounts/${accountLabel}/simulate-incoming-transaction`,
- baseUrl,
- );
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- body: req,
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- }
-
- export async function getAccountTransactions(
- libeufinSandboxService: LibeufinSandboxServiceInterface,
- accountLabel: string,
- ): Promise<SandboxAccountTransactions> {
- const baseUrl = libeufinSandboxService.baseUrl;
- let url = new URL(
- `admin/bank-accounts/${accountLabel}/transactions`,
- baseUrl,
- );
- const res = await libeufinHarnessHttpLib.fetch(url.href, {
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- return (await res.json()) as SandboxAccountTransactions;
- }
-
- export async function getCamt053(
- libeufinSandboxService: LibeufinSandboxServiceInterface,
- accountLabel: string,
- ): Promise<any> {
- const baseUrl = libeufinSandboxService.baseUrl;
- let url = new URL("admin/payments/camt", baseUrl);
- return await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: {
- bankaccount: accountLabel,
- type: 53,
- },
- });
- }
-
- export async function getAccountInfoWithBalance(
- libeufinSandboxService: LibeufinSandboxServiceInterface,
- accountLabel: string,
- ): Promise<LibeufinSandboxAdminBankAccountBalance> {
- const baseUrl = libeufinSandboxService.baseUrl;
- let url = new URL(`admin/bank-accounts/${accountLabel}`, baseUrl);
- const res = await libeufinHarnessHttpLib.fetch(url.href, {
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- return res.json();
- }
-}
-
-export namespace LibeufinNexusApi {
- export async function getAllConnections(
- nexus: LibeufinNexusServiceInterface,
- ): Promise<NexusBankConnections> {
- let url = new URL("bank-connections", nexus.baseUrl);
- const res = await libeufinHarnessHttpLib.fetch(url.href, {
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- return res.json();
- }
-
- export async function deleteBankConnection(
- libeufinNexusService: LibeufinNexusServiceInterface,
- req: DeleteBankConnectionRequest,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL("bank-connections/delete-connection", baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: req,
- });
- }
-
- export async function createEbicsBankConnection(
- libeufinNexusService: LibeufinNexusServiceInterface,
- req: CreateEbicsBankConnectionRequest,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL("bank-connections", baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: {
- source: "new",
- type: "ebics",
- name: req.name,
- data: {
- ebicsURL: req.ebicsURL,
- hostID: req.hostID,
- userID: req.userID,
- partnerID: req.partnerID,
- systemID: req.systemID,
- },
- },
- });
- }
-
- export async function getBankAccount(
- libeufinNexusService: LibeufinNexusServiceInterface,
- accountName: string,
- ): Promise<any> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(`bank-accounts/${accountName}`, baseUrl);
- const resp = await libeufinHarnessHttpLib.fetch(url.href, {
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- return resp.json();
- }
-
- export async function submitInitiatedPayment(
- libeufinNexusService: LibeufinNexusServiceInterface,
- accountName: string,
- paymentId: string,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(
- `bank-accounts/${accountName}/payment-initiations/${paymentId}/submit`,
- baseUrl,
- );
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: {},
- });
- }
-
- export async function fetchAccounts(
- libeufinNexusService: LibeufinNexusServiceInterface,
- connectionName: string,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(
- `bank-connections/${connectionName}/fetch-accounts`,
- baseUrl,
- );
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: {},
- });
- }
-
- export async function importConnectionAccount(
- libeufinNexusService: LibeufinNexusServiceInterface,
- connectionName: string,
- offeredAccountId: string,
- nexusBankAccountId: string,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(
- `bank-connections/${connectionName}/import-account`,
- baseUrl,
- );
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: {
- offeredAccountId,
- nexusBankAccountId,
- },
- });
- }
-
- export async function connectBankConnection(
- libeufinNexusService: LibeufinNexusServiceInterface,
- connectionName: string,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(`bank-connections/${connectionName}/connect`, baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: {},
- });
- }
-
- export async function getPaymentInitiations(
- libeufinNexusService: LibeufinNexusServiceInterface,
- accountName: string,
- username: string = "admin",
- password: string = "test",
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(
- `/bank-accounts/${accountName}/payment-initiations`,
- baseUrl,
- );
- let response = await libeufinHarnessHttpLib.fetch(url.href, {
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- const respJson = await response.json();
- console.log(
- `Payment initiations of: ${accountName}`,
- JSON.stringify(respJson, null, 2),
- );
- }
-
- // Uses the Anastasis API to get a list of transactions.
- export async function getAnastasisTransactions(
- libeufinNexusService: LibeufinNexusServiceInterface,
- anastasisBaseUrl: string,
- // FIXME: Nail down type!
- params: {}, // of the request: {delta: 5, ..}
- username: string = "admin",
- password: string = "test",
- ): Promise<any> {
- let url = new URL("history/incoming", anastasisBaseUrl);
- for (const [k, v] of Object.entries(params)) {
- url.searchParams.set(k, String(v));
- }
- let response = await libeufinHarnessHttpLib.fetch(url.href, {
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- return response.json();
- }
-
- // FIXME: this function should return some structured
- // object that represents a history.
- export async function getAccountTransactions(
- libeufinNexusService: LibeufinNexusServiceInterface,
- accountName: string,
- username: string = "admin",
- password: string = "test",
- ): Promise<LibeufinNexusTransactions> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(`/bank-accounts/${accountName}/transactions`, baseUrl);
- let response = await libeufinHarnessHttpLib.fetch(url.href, {
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- return response.json();
- }
-
- export async function fetchTransactions(
- libeufinNexusService: LibeufinNexusServiceInterface,
- accountName: string,
- rangeType: string = "all",
- level: string = "report",
- username: string = "admin",
- password: string = "test",
- ): Promise<NexusNewTransactionsInfo> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(
- `/bank-accounts/${accountName}/fetch-transactions`,
- baseUrl,
- );
- const resp = await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: {
- rangeType: rangeType,
- level: level,
- },
- });
- return resp.json();
- }
-
- export async function changePassword(
- libeufinNexusService: LibeufinNexusServiceInterface,
- username: string,
- req: UpdateNexusUserRequest,
- auth: NexusAuth,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(`/users/${username}/password`, baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: req,
- });
- }
-
- export async function getUser(
- libeufinNexusService: LibeufinNexusServiceInterface,
- auth: NexusAuth,
- ): Promise<NexusUserResponse> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(`/user`, baseUrl);
- const resp = await libeufinHarnessHttpLib.fetch(url.href, {
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- return resp.json();
- }
-
- export async function createUser(
- libeufinNexusService: LibeufinNexusServiceInterface,
- req: CreateNexusUserRequest,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(`/users`, baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: req,
- });
- }
-
- export async function getAllPermissions(
- libeufinNexusService: LibeufinNexusServiceInterface,
- ): Promise<NexusGetPermissionsResponse> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(`/permissions`, baseUrl);
- const resp = await libeufinHarnessHttpLib.fetch(url.href, {
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- return resp.json();
- }
-
- export async function postPermission(
- libeufinNexusService: LibeufinNexusServiceInterface,
- req: PostNexusPermissionRequest,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(`/permissions`, baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: req,
- });
- }
-
- export async function getAllTasks(
- libeufinNexusService: LibeufinNexusServiceInterface,
- bankAccountName: string,
- ): Promise<NexusTaskCollection> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(`/bank-accounts/${bankAccountName}/schedule`, baseUrl);
- const resp = await libeufinHarnessHttpLib.fetch(url.href, {
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- return resp.json();
- }
-
- export async function getTask(
- libeufinNexusService: LibeufinNexusServiceInterface,
- bankAccountName: string,
- // When void, the request returns the list of all the
- // tasks under this bank account.
- taskName: string,
- ): Promise<NexusTask> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(
- `/bank-accounts/${bankAccountName}/schedule/${taskName}`,
- baseUrl,
- );
- if (taskName) url = new URL(taskName, `${url.href}/`);
- const resp = await libeufinHarnessHttpLib.fetch(url.href, {
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- return resp.json();
- }
-
- export async function deleteTask(
- libeufinNexusService: LibeufinNexusServiceInterface,
- bankAccountName: string,
- taskName: string,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(
- `/bank-accounts/${bankAccountName}/schedule/${taskName}`,
- baseUrl,
- );
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "DELETE",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- }
-
- export async function postTask(
- libeufinNexusService: LibeufinNexusServiceInterface,
- bankAccountName: string,
- req: PostNexusTaskRequest,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(`/bank-accounts/${bankAccountName}/schedule`, baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: req,
- });
- }
-
- export async function deleteFacade(
- libeufinNexusService: LibeufinNexusServiceInterface,
- facadeName: string,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(`facades/${facadeName}`, baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "DELETE",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- }
-
- export async function getAllFacades(
- libeufinNexusService: LibeufinNexusServiceInterface,
- ): Promise<NexusFacadeListResponse> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL("facades", baseUrl);
- const resp = await libeufinHarnessHttpLib.fetch(url.href, {
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- });
- // FIXME: Just return validated, typed response here!
- return resp.json();
- }
-
- export async function createAnastasisFacade(
- libeufinNexusService: LibeufinNexusServiceInterface,
- req: CreateAnastasisFacadeRequest,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL("facades", baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: {
- name: req.name,
- type: "anastasis",
- config: {
- bankAccount: req.accountName,
- bankConnection: req.connectionName,
- currency: req.currency,
- reserveTransferLevel: req.reserveTransferLevel,
- },
- },
- });
- }
-
- export async function createTwgFacade(
- libeufinNexusService: LibeufinNexusServiceInterface,
- req: CreateTalerWireGatewayFacadeRequest,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL("facades", baseUrl);
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: {
- name: req.name,
- type: "taler-wire-gateway",
- config: {
- bankAccount: req.accountName,
- bankConnection: req.connectionName,
- currency: req.currency,
- reserveTransferLevel: req.reserveTransferLevel,
- },
- },
- });
- }
-
- export async function submitAllPaymentInitiations(
- libeufinNexusService: LibeufinNexusServiceInterface,
- accountId: string,
- ): Promise<void> {
- const baseUrl = libeufinNexusService.baseUrl;
- let url = new URL(
- `/bank-accounts/${accountId}/submit-all-payment-initiations`,
- baseUrl,
- );
- await libeufinHarnessHttpLib.fetch(url.href, {
- method: "POST",
- headers: { Authorization: makeBasicAuthHeader("admin", "secret") },
- body: {},
- });
- }
-}
diff --git a/packages/taler-harness/src/harness/libeufin.ts b/packages/taler-harness/src/harness/libeufin.ts
deleted file mode 100644
index caeea85ae..000000000
--- a/packages/taler-harness/src/harness/libeufin.ts
+++ /dev/null
@@ -1,1047 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 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/>
- */
-
-/**
- * This file defines euFin test logic that needs state
- * and that depends on the main harness.ts. The other
- * definitions - mainly helper functions to call RESTful
- * APIs - moved to libeufin-apis.ts. That enables harness.ts
- * to depend on such API calls, in contrast to the previous
- * situation where harness.ts had to include this file causing
- * a circular dependency. */
-
-/**
- * Imports.
- */
-import { AmountString, Logger } from "@gnu-taler/taler-util";
-import {
- DbInfo,
- GlobalTestState,
- ProcessWrapper,
- getRandomIban,
- pingProc,
- runCommand,
- setupDb,
- sh,
-} from "../harness/harness.js";
-import {
- CreateAnastasisFacadeRequest,
- CreateEbicsBankAccountRequest,
- CreateEbicsBankConnectionRequest,
- CreateNexusUserRequest,
- CreateTalerWireGatewayFacadeRequest,
- LibeufinNexusApi,
- LibeufinSandboxApi,
- LibeufinSandboxServiceInterface,
- PostNexusPermissionRequest,
-} from "../harness/libeufin-apis.js";
-
-const logger = new Logger("libeufin.ts");
-
-export { LibeufinNexusApi, LibeufinSandboxApi };
-
-export interface LibeufinServices {
- libeufinSandbox: LibeufinSandboxService;
- libeufinNexus: LibeufinNexusService;
- commonDb: DbInfo;
-}
-
-export interface LibeufinSandboxConfig {
- httpPort: number;
- databaseJdbcUri: string;
-}
-
-export interface LibeufinNexusConfig {
- httpPort: number;
- databaseJdbcUri: string;
-}
-
-export interface LibeufinNexusMoneyMovement {
- amount: string;
- creditDebitIndicator: string;
- details: {
- debtor: {
- name: string;
- };
- debtorAccount: {
- iban: string;
- };
- debtorAgent: {
- bic: string;
- };
- creditor: {
- name: string;
- };
- creditorAccount: {
- iban: string;
- };
- creditorAgent: {
- bic: string;
- };
- endToEndId: string;
- unstructuredRemittanceInformation: string;
- };
-}
-
-export interface LibeufinNexusBatches {
- batchTransactions: Array<LibeufinNexusMoneyMovement>;
-}
-
-export interface LibeufinNexusTransaction {
- amount: string;
- creditDebitIndicator: string;
- status: string;
- bankTransactionCode: string;
- valueDate: string;
- bookingDate: string;
- accountServicerRef: string;
- batches: Array<LibeufinNexusBatches>;
-}
-
-export interface LibeufinNexusTransactions {
- transactions: Array<LibeufinNexusTransaction>;
-}
-
-export interface LibeufinCliDetails {
- nexusUrl: string;
- sandboxUrl: string;
- nexusDatabaseUri: string;
- sandboxDatabaseUri: string;
- nexusUser: LibeufinNexusUser;
-}
-
-export interface LibeufinEbicsSubscriberDetails {
- hostId: string;
- partnerId: string;
- userId: string;
-}
-
-export interface LibeufinEbicsConnectionDetails {
- subscriberDetails: LibeufinEbicsSubscriberDetails;
- ebicsUrl: string;
- connectionName: string;
-}
-
-export interface LibeufinBankAccountDetails {
- currency: string;
- iban: string;
- bic: string;
- personName: string;
- accountName: string;
-}
-
-export interface LibeufinNexusUser {
- username: string;
- password: string;
-}
-
-export interface LibeufinBackupFileDetails {
- passphrase: string;
- outputFile: string;
- connectionName: string;
-}
-
-export interface LibeufinKeyLetterDetails {
- outputFile: string;
- connectionName: string;
-}
-
-export interface LibeufinBankAccountImportDetails {
- offeredBankAccountName: string;
- nexusBankAccountName: string;
- connectionName: string;
-}
-
-export interface LibeufinPreparedPaymentDetails {
- creditorIban: string;
- creditorBic: string;
- creditorName: string;
- subject: string;
- amount: string;
- currency: string;
- nexusBankAccountName: string;
-}
-
-export interface NexusBankConnection {
- // connection type. For example "ebics".
- type: string;
-
- // connection name as given by the user at
- // the moment of creation.
- name: string;
-}
-
-export interface NexusBankConnections {
- bankConnections: NexusBankConnection[];
-}
-
-export interface FacadeShowInfo {
- // Name of the facade, same as the "fcid" parameter.
- name: string;
-
- // Type of the facade.
- // For example, "taler-wire-gateway".
- type: string;
-
- // Bas URL of the facade.
- baseUrl: string;
-
- // details depending on the facade type.
- config: any;
-}
-
-export interface FetchParams {
- // Because transactions are delivered by banks in "batches",
- // then every batch can have different qualities. This value
- // lets the request specify which type of batch ought to be
- // returned. Currently, the following two type are supported:
- //
- // 'report': typically includes only non booked transactions.
- // 'statement': typically includes only booked transactions.
- level: "report" | "statement" | "all";
-
- // This type indicates the time range of the query.
- // It allows the following values:
- //
- // 'latest': retrieves the last transactions from the bank.
- // If there are older unread transactions, those will *not*
- // be downloaded.
- //
- // 'all': retrieves all the transactions from the bank,
- // until the oldest.
- //
- // 'previous-days': currently *not* implemented, it will allow
- // the request to download transactions from
- // today until N days before.
- //
- // 'since-last': retrieves all the transactions since the last
- // time one was downloaded.
- //
- rangeType: "latest" | "all" | "previous-days" | "since-last";
-}
-
-export interface NexusTask {
- // The resource being impacted by this operation.
- // Typically a (Nexus) bank account being fetched
- // or whose payments are submitted. In this cases,
- // this value is the "bank-account" constant.
- resourceType: string;
- // Name of the resource. In case of "bank-account", that
- // is the name under which the bank account was imported
- // from the bank.
- resourceId: string;
- // Task name, equals 'taskId'
- taskName: string;
- // Values allowed are "fetch" or "submit".
- taskType: string;
- // FIXME: describe.
- taskCronSpec: string;
- // Only meaningful for "fetch" types.
- taskParams: FetchParams;
- // Timestamp in seconds when the next iteration will run.
- nextScheduledExecutionSec: number;
- // Timestamp in seconds when the previous iteration ran.
- prevScheduledExecutionSec: number;
-}
-
-export interface NexusNewTransactionsInfo {
- // How many transactions are new to Nexus.
- newTransactions: number;
- // How many transactions got downloaded by the request.
- // Note that a transaction can be downloaded multiple
- // times but only counts as new once.
- downloadedTransactions: number;
-}
-
-
-export interface NexusUserResponse {
- // User name
- username: string;
-
- // Is this a super user?
- superuser: boolean;
-}
-
-export interface NexusTaskShortInfo {
- cronspec: string;
- type: "fetch" | "submit";
- params: FetchParams;
-}
-
-export interface NexusTaskCollection {
- // This field can contain *multiple* objects of the type sampled below.
- schedule: {
- [taskName: string]: NexusTaskShortInfo;
- };
-}
-
-export interface NexusFacadeListResponse {
- facades: FacadeShowInfo[];
-}
-
-export interface LibeufinSandboxAdminBankAccountBalance {
- // Balance in the $currency:$amount format.
- balance: AmountString;
- // IBAN of the bank account identified by $accountLabel
- iban: string;
- // BIC of the bank account identified by $accountLabel
- bic: string;
- // Mentions $accountLabel
- label: string;
-}
-
-export interface LibeufinPermission {
- subjectType: string;
- subjectId: string;
- resourceType: string;
- resourceId: string;
- permissionName: string;
-}
-
-export interface NexusGetPermissionsResponse {
- permissions: LibeufinPermission[];
-}
-
-export class LibeufinSandboxService implements LibeufinSandboxServiceInterface {
- static async create(
- gc: GlobalTestState,
- sandboxConfig: LibeufinSandboxConfig,
- ): Promise<LibeufinSandboxService> {
- return new LibeufinSandboxService(gc, sandboxConfig);
- }
-
- sandboxProc: ProcessWrapper | undefined;
- globalTestState: GlobalTestState;
-
- constructor(
- gc: GlobalTestState,
- private sandboxConfig: LibeufinSandboxConfig,
- ) {
- this.globalTestState = gc;
- }
-
- get baseUrl(): string {
- return `http://localhost:${this.sandboxConfig.httpPort}/`;
- }
-
- async start(): Promise<void> {
- await sh(
- this.globalTestState,
- "libeufin-sandbox-config",
- "libeufin-sandbox config default",
- {
- ...process.env,
- LIBEUFIN_SANDBOX_DB_CONNECTION: this.sandboxConfig.databaseJdbcUri,
- },
- );
-
- this.sandboxProc = this.globalTestState.spawnService(
- "libeufin-sandbox",
- ["serve", "--port", `${this.sandboxConfig.httpPort}`],
- "libeufin-sandbox",
- {
- ...process.env,
- LIBEUFIN_SANDBOX_DB_CONNECTION: this.sandboxConfig.databaseJdbcUri,
- LIBEUFIN_SANDBOX_ADMIN_PASSWORD: "secret",
- },
- );
- }
-
- async c53tick(): Promise<string> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-sandbox-c53tick",
- "libeufin-sandbox camt053tick",
- {
- ...process.env,
- LIBEUFIN_SANDBOX_DB_CONNECTION: this.sandboxConfig.databaseJdbcUri,
- },
- );
- return stdout;
- }
-
- async makeTransaction(
- debit: string,
- credit: string,
- amount: string, // $currency:x.y
- subject: string,
- ): Promise<string> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-sandbox-maketransfer",
- `libeufin-sandbox make-transaction --debit-account=${debit} --credit-account=${credit} ${amount} "${subject}"`,
- {
- ...process.env,
- LIBEUFIN_SANDBOX_DB_CONNECTION: this.sandboxConfig.databaseJdbcUri,
- },
- );
- return stdout;
- }
-
- async pingUntilAvailable(): Promise<void> {
- const url = this.baseUrl;
- await pingProc(this.sandboxProc, url, "libeufin-sandbox");
- }
-}
-
-export class LibeufinNexusService {
- static async create(
- gc: GlobalTestState,
- nexusConfig: LibeufinNexusConfig,
- ): Promise<LibeufinNexusService> {
- return new LibeufinNexusService(gc, nexusConfig);
- }
-
- nexusProc: ProcessWrapper | undefined;
- globalTestState: GlobalTestState;
-
- constructor(gc: GlobalTestState, private nexusConfig: LibeufinNexusConfig) {
- this.globalTestState = gc;
- }
-
- get baseUrl(): string {
- return `http://localhost:${this.nexusConfig.httpPort}/`;
- }
-
- async start(): Promise<void> {
- await runCommand(
- this.globalTestState,
- "libeufin-nexus-superuser",
- "libeufin-nexus",
- ["superuser", "admin", "--password", "test"],
- {
- ...process.env,
- LIBEUFIN_NEXUS_DB_CONNECTION: this.nexusConfig.databaseJdbcUri,
- },
- );
-
- this.nexusProc = this.globalTestState.spawnService(
- "libeufin-nexus",
- ["serve", "--port", `${this.nexusConfig.httpPort}`],
- "libeufin-nexus",
- {
- ...process.env,
- LIBEUFIN_NEXUS_DB_CONNECTION: this.nexusConfig.databaseJdbcUri,
- },
- );
- }
-
- async pingUntilAvailable(): Promise<void> {
- const url = `${this.baseUrl}config`;
- await pingProc(this.nexusProc, url, "libeufin-nexus");
- }
-
- async createNexusSuperuser(details: LibeufinNexusUser): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-nexus",
- `libeufin-nexus superuser ${details.username} --password=${details.password}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_DB_CONNECTION: this.nexusConfig.databaseJdbcUri,
- },
- );
- console.log(stdout);
- }
-}
-
-export interface TwgAddIncomingRequest {
- amount: string;
- reserve_pub: string;
- debit_account: string;
-}
-
-/**
- * The bundle aims at minimizing the amount of input
- * data that is required to initialize a new user + Ebics
- * connection.
- */
-export class NexusUserBundle {
- userReq: CreateNexusUserRequest;
- connReq: CreateEbicsBankConnectionRequest;
- anastasisReq: CreateAnastasisFacadeRequest;
- twgReq: CreateTalerWireGatewayFacadeRequest;
- twgTransferPermission: PostNexusPermissionRequest;
- twgHistoryPermission: PostNexusPermissionRequest;
- twgAddIncomingPermission: PostNexusPermissionRequest;
- localAccountName: string;
- remoteAccountName: string;
-
- constructor(salt: string, ebicsURL: string) {
- this.userReq = {
- username: `username-${salt}`,
- password: `password-${salt}`,
- };
-
- this.connReq = {
- name: `connection-${salt}`,
- ebicsURL: ebicsURL,
- hostID: `ebicshost,${salt}`,
- partnerID: `ebicspartner,${salt}`,
- userID: `ebicsuser,${salt}`,
- };
-
- this.twgReq = {
- currency: "EUR",
- name: `twg-${salt}`,
- reserveTransferLevel: "report",
- accountName: `local-account-${salt}`,
- connectionName: `connection-${salt}`,
- };
- this.anastasisReq = {
- currency: "EUR",
- name: `anastasis-${salt}`,
- reserveTransferLevel: "report",
- accountName: `local-account-${salt}`,
- connectionName: `connection-${salt}`,
- };
- this.remoteAccountName = `remote-account-${salt}`;
- this.localAccountName = `local-account-${salt}`;
- this.twgTransferPermission = {
- action: "grant",
- permission: {
- subjectId: `username-${salt}`,
- subjectType: "user",
- resourceType: "facade",
- resourceId: `twg-${salt}`,
- permissionName: "facade.talerWireGateway.transfer",
- },
- };
- this.twgHistoryPermission = {
- action: "grant",
- permission: {
- subjectId: `username-${salt}`,
- subjectType: "user",
- resourceType: "facade",
- resourceId: `twg-${salt}`,
- permissionName: "facade.talerWireGateway.history",
- },
- };
- }
-}
-
-/**
- * The bundle aims at minimizing the amount of input
- * data that is required to initialize a new Sandbox
- * customer, associating their bank account with a Ebics
- * subscriber.
- */
-export class SandboxUserBundle {
- ebicsBankAccount: CreateEbicsBankAccountRequest;
- constructor(salt: string) {
- this.ebicsBankAccount = {
- bic: "BELADEBEXXX",
- iban: getRandomIban(),
- label: `remote-account-${salt}`,
- name: `Taler Exchange: ${salt}`,
- subscriber: {
- hostID: `ebicshost,${salt}`,
- partnerID: `ebicspartner,${salt}`,
- userID: `ebicsuser,${salt}`,
- },
- };
- }
-}
-
-export class LibeufinCli {
- cliDetails: LibeufinCliDetails;
- globalTestState: GlobalTestState;
-
- constructor(gc: GlobalTestState, cd: LibeufinCliDetails) {
- this.globalTestState = gc;
- this.cliDetails = cd;
- }
-
- env(): any {
- return {
- ...process.env,
- LIBEUFIN_SANDBOX_URL: this.cliDetails.sandboxUrl,
- LIBEUFIN_SANDBOX_USERNAME: "admin",
- LIBEUFIN_SANDBOX_PASSWORD: "secret",
- };
- }
-
- async checkSandbox(): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-checksandbox",
- "libeufin-cli sandbox check",
- this.env(),
- );
- }
-
- async registerBankCustomer(
- username: string,
- password: string,
- ): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-registercustomer",
- "libeufin-cli sandbox demobank register --name='Test Customer'",
- {
- ...process.env,
- LIBEUFIN_SANDBOX_URL: this.cliDetails.sandboxUrl + "/demobanks/default",
- LIBEUFIN_SANDBOX_USERNAME: username,
- LIBEUFIN_SANDBOX_PASSWORD: password,
- },
- );
- console.log(stdout);
- }
-
- async createEbicsHost(hostId: string): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-createebicshost",
- `libeufin-cli sandbox ebicshost create --host-id=${hostId}`,
- this.env(),
- );
- console.log(stdout);
- }
-
- async createEbicsSubscriber(
- details: LibeufinEbicsSubscriberDetails,
- ): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-createebicssubscriber",
- "libeufin-cli sandbox ebicssubscriber create" +
- ` --host-id=${details.hostId}` +
- ` --partner-id=${details.partnerId}` +
- ` --user-id=${details.userId}`,
- this.env(),
- );
- console.log(stdout);
- }
-
- async createEbicsBankAccount(
- sd: LibeufinEbicsSubscriberDetails,
- bankAccountDetails: LibeufinBankAccountDetails,
- ): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-createebicsbankaccount",
- "libeufin-cli sandbox ebicsbankaccount create" +
- ` --iban=${bankAccountDetails.iban}` +
- ` --bic=${bankAccountDetails.bic}` +
- ` --person-name='${bankAccountDetails.personName}'` +
- ` --account-name=${bankAccountDetails.accountName}` +
- ` --ebics-host-id=${sd.hostId}` +
- ` --ebics-partner-id=${sd.partnerId}` +
- ` --ebics-user-id=${sd.userId}`,
- this.env(),
- );
- console.log(stdout);
- }
-
- async generateTransactions(accountName: string): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-generatetransactions",
- `libeufin-cli sandbox bankaccount generate-transactions ${accountName}`,
- this.env(),
- );
- console.log(stdout);
- }
-
- async showSandboxTransactions(accountName: string): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-showsandboxtransactions",
- `libeufin-cli sandbox bankaccount transactions ${accountName}`,
- this.env(),
- );
- console.log(stdout);
- }
-
- async createEbicsConnection(
- connectionDetails: LibeufinEbicsConnectionDetails,
- ): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-createebicsconnection",
- `libeufin-cli connections new-ebics-connection` +
- ` --ebics-url=${connectionDetails.ebicsUrl}` +
- ` --host-id=${connectionDetails.subscriberDetails.hostId}` +
- ` --partner-id=${connectionDetails.subscriberDetails.partnerId}` +
- ` --ebics-user-id=${connectionDetails.subscriberDetails.userId}` +
- ` ${connectionDetails.connectionName}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async createBackupFile(details: LibeufinBackupFileDetails): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-createbackupfile",
- `libeufin-cli connections export-backup` +
- ` --passphrase=${details.passphrase}` +
- ` --output-file=${details.outputFile}` +
- ` ${details.connectionName}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async createKeyLetter(details: LibeufinKeyLetterDetails): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-createkeyletter",
- `libeufin-cli connections get-key-letter` +
- ` ${details.connectionName} ${details.outputFile}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async connect(connectionName: string): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-connect",
- `libeufin-cli connections connect ${connectionName}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async downloadBankAccounts(connectionName: string): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-downloadbankaccounts",
- `libeufin-cli connections download-bank-accounts ${connectionName}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async listOfferedBankAccounts(connectionName: string): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-listofferedbankaccounts",
- `libeufin-cli connections list-offered-bank-accounts ${connectionName}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async importBankAccount(
- importDetails: LibeufinBankAccountImportDetails,
- ): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-importbankaccount",
- "libeufin-cli connections import-bank-account" +
- ` --offered-account-id=${importDetails.offeredBankAccountName}` +
- ` --nexus-bank-account-id=${importDetails.nexusBankAccountName}` +
- ` ${importDetails.connectionName}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async fetchTransactions(bankAccountName: string): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-fetchtransactions",
- `libeufin-cli accounts fetch-transactions ${bankAccountName}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async transactions(bankAccountName: string): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-transactions",
- `libeufin-cli accounts transactions ${bankAccountName}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async preparePayment(details: LibeufinPreparedPaymentDetails): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-preparepayment",
- `libeufin-cli accounts prepare-payment` +
- ` --creditor-iban=${details.creditorIban}` +
- ` --creditor-bic=${details.creditorBic}` +
- ` --creditor-name='${details.creditorName}'` +
- ` --payment-subject='${details.subject}'` +
- ` --payment-amount=${details.currency}:${details.amount}` +
- ` ${details.nexusBankAccountName}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async submitPayment(
- details: LibeufinPreparedPaymentDetails,
- paymentUuid: string,
- ): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-submitpayments",
- `libeufin-cli accounts submit-payments` +
- ` --payment-uuid=${paymentUuid}` +
- ` ${details.nexusBankAccountName}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async newAnastasisFacade(req: NewAnastasisFacadeReq): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-new-anastasis-facade",
- `libeufin-cli facades new-anastasis-facade` +
- ` --currency ${req.currency}` +
- ` --facade-name ${req.facadeName}` +
- ` ${req.connectionName} ${req.accountName}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async newTalerWireGatewayFacade(req: NewTalerWireGatewayReq): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-new-taler-wire-gateway-facade",
- `libeufin-cli facades new-taler-wire-gateway-facade` +
- ` --currency ${req.currency}` +
- ` --facade-name ${req.facadeName}` +
- ` ${req.connectionName} ${req.accountName}`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-
- async listFacades(): Promise<void> {
- const stdout = await sh(
- this.globalTestState,
- "libeufin-cli-facades-list",
- `libeufin-cli facades list`,
- {
- ...process.env,
- LIBEUFIN_NEXUS_URL: this.cliDetails.nexusUrl,
- LIBEUFIN_NEXUS_USERNAME: this.cliDetails.nexusUser.username,
- LIBEUFIN_NEXUS_PASSWORD: this.cliDetails.nexusUser.password,
- },
- );
- console.log(stdout);
- }
-}
-
-interface NewAnastasisFacadeReq {
- facadeName: string;
- connectionName: string;
- accountName: string;
- currency: string;
-}
-
-interface NewTalerWireGatewayReq {
- facadeName: string;
- connectionName: string;
- accountName: string;
- currency: string;
-}
-
-/**
- * Launch Nexus and Sandbox AND creates users / facades / bank accounts /
- * .. all that's required to start making bank traffic.
- */
-export async function launchLibeufinServices(
- t: GlobalTestState,
- nexusUserBundle: NexusUserBundle[],
- sandboxUserBundle: SandboxUserBundle[] = [],
- withFacades: string[] = [], // takes only "twg" and/or "anastasis"
-): Promise<LibeufinServices> {
- const db = await setupDb(t);
-
- const libeufinSandbox = await LibeufinSandboxService.create(t, {
- httpPort: 5010,
- databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-sandbox.sqlite3`,
- });
-
- await libeufinSandbox.start();
- await libeufinSandbox.pingUntilAvailable();
-
- const libeufinNexus = await LibeufinNexusService.create(t, {
- httpPort: 5011,
- databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-nexus.sqlite3`,
- });
-
- await libeufinNexus.start();
- await libeufinNexus.pingUntilAvailable();
- console.log("Libeufin services launched!");
-
- for (let sb of sandboxUserBundle) {
- await LibeufinSandboxApi.createEbicsHost(
- libeufinSandbox,
- sb.ebicsBankAccount.subscriber.hostID,
- );
- await LibeufinSandboxApi.createEbicsSubscriber(
- libeufinSandbox,
- sb.ebicsBankAccount.subscriber,
- );
- await LibeufinSandboxApi.createDemobankAccount(
- sb.ebicsBankAccount.label,
- "password-unused",
- { baseUrl: libeufinSandbox.baseUrl + "/demobanks/default/access-api/" },
- );
- await LibeufinSandboxApi.createDemobankEbicsSubscriber(
- sb.ebicsBankAccount.subscriber,
- sb.ebicsBankAccount.label,
- { baseUrl: libeufinSandbox.baseUrl + "/demobanks/default/" },
- );
- }
- console.log("Sandbox user(s) / account(s) / subscriber(s): created");
-
- for (let nb of nexusUserBundle) {
- await LibeufinNexusApi.createEbicsBankConnection(libeufinNexus, nb.connReq);
- await LibeufinNexusApi.connectBankConnection(
- libeufinNexus,
- nb.connReq.name,
- );
- await LibeufinNexusApi.fetchAccounts(libeufinNexus, nb.connReq.name);
- await LibeufinNexusApi.importConnectionAccount(
- libeufinNexus,
- nb.connReq.name,
- nb.remoteAccountName,
- nb.localAccountName,
- );
- await LibeufinNexusApi.createUser(libeufinNexus, nb.userReq);
- for (let facade of withFacades) {
- switch (facade) {
- case "twg":
- await LibeufinNexusApi.createTwgFacade(libeufinNexus, nb.twgReq);
- await LibeufinNexusApi.postPermission(
- libeufinNexus,
- nb.twgTransferPermission,
- );
- await LibeufinNexusApi.postPermission(
- libeufinNexus,
- nb.twgHistoryPermission,
- );
- break;
- case "anastasis":
- await LibeufinNexusApi.createAnastasisFacade(
- libeufinNexus,
- nb.anastasisReq,
- );
- }
- }
- }
- console.log(
- "Nexus user(s) / connection(s) / facade(s) / permission(s): created",
- );
-
- return {
- commonDb: db,
- libeufinNexus: libeufinNexus,
- libeufinSandbox: libeufinSandbox,
- };
-}
-
-/**
- * Helper function that searches a payment among
- * a list, as returned by Nexus. The key is just
- * the payment subject.
- */
-export function findNexusPayment(
- key: string,
- payments: LibeufinNexusTransactions,
-): LibeufinNexusMoneyMovement | void {
- let transactions = payments["transactions"];
- for (let i = 0; i < transactions.length; i++) {
- //FIXME: last line won't compile with the current definition of the type
- //@ts-ignore
- let batches = transactions[i]["camtData"]["batches"];
- for (let y = 0; y < batches.length; y++) {
- let movements = batches[y]["batchTransactions"];
- for (let z = 0; z < movements.length; z++) {
- let movement = movements[z];
- if (movement["details"]["unstructuredRemittanceInformation"] == key)
- return movement;
- }
- }
- }
-}