From ee48a39eb370e65564317f7c77e2cd52e8a0c42f Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 14 Sep 2023 10:56:34 -0300 Subject: merchant payment --- .../src/util/coinSelection.test.ts | 103 +++++++++++++++++---- .../taler-wallet-core/src/util/coinSelection.ts | 5 +- 2 files changed, 87 insertions(+), 21 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/util/coinSelection.test.ts b/packages/taler-wallet-core/src/util/coinSelection.test.ts index 2a322c4a9..f809c4e60 100644 --- a/packages/taler-wallet-core/src/util/coinSelection.test.ts +++ b/packages/taler-wallet-core/src/util/coinSelection.test.ts @@ -24,23 +24,7 @@ import { TransactionAmountMode, } from "@gnu-taler/taler-util"; import test, { ExecutionContext } from "ava"; -import { AvailableDenom, testing_greedySelectPeer } from "./coinSelection.js" - -type Tester = { - deep: { - equal(another: T): ReturnType; - equals(another: T): ReturnType; - } -} - -function expect(t: ExecutionContext, thing: T): Tester { - return { - deep: { - equal: (another: T) => t.deepEqual(thing, another), - equals: (another: T) => t.deepEqual(thing, another), - }, - }; -} +import { AvailableDenom, testing_greedySelectPeer, testing_selectGreedy } from "./coinSelection.js" const inTheDistantFuture = AbsoluteTime.toProtocolTimestamp( AbsoluteTime.addDuration(AbsoluteTime.now(), Duration.fromSpec({ hours: 1 })) @@ -49,7 +33,7 @@ const inThePast = AbsoluteTime.toProtocolTimestamp( AbsoluteTime.subtractDuraction(AbsoluteTime.now(), Duration.fromSpec({ hours: 1 })) ) -test("should select the coin", (t) => { +test("p2p: should select the coin", (t) => { const instructedAmount = Amounts.parseOrThrow("LOCAL:2") const tally = { amountAcc: Amounts.zeroOfCurrency(instructedAmount.currency), @@ -84,7 +68,7 @@ test("should select the coin", (t) => { }); -test("should select 3 coins", (t) => { +test("p2p: should select 3 coins", (t) => { const instructedAmount = Amounts.parseOrThrow("LOCAL:20") const tally = { amountAcc: Amounts.zeroOfCurrency(instructedAmount.currency), @@ -123,7 +107,7 @@ test("should select 3 coins", (t) => { }); -test("can't select since the instructed amount is too high", (t) => { +test("p2p: can't select since the instructed amount is too high", (t) => { const instructedAmount = Amounts.parseOrThrow("LOCAL:60") const tally = { amountAcc: Amounts.zeroOfCurrency(instructedAmount.currency), @@ -151,6 +135,68 @@ test("can't select since the instructed amount is too high", (t) => { }); +test("pay: select one coin to pay with fee", (t) => { + const payment = Amounts.parseOrThrow("LOCAL:2") + const exchangeWireFee = Amounts.parseOrThrow("LOCAL:0.1") + const zero = Amounts.zeroOfCurrency(payment.currency) + const tally = { + amountPayRemaining: payment, + amountWireFeeLimitRemaining: zero, + amountDepositFeeLimitRemaining: zero, + customerDepositFees: zero, + customerWireFees: zero, + wireFeeCoveredForExchange: new Set(), + lastDepositFee: zero, + }; + const coins = testing_selectGreedy( + { + "auditors": [], + "exchanges": [ + { + "exchangeBaseUrl": "http://exchange.localhost/", + "exchangePub": "E5M8CGRDHXF1RCVP3B8TQCTDYNQ7T4XHWR5SVEQRGVVMVME41VJ0" + } + ], + "contractTermsAmount": payment, + "depositFeeLimit": zero, + "wireFeeAmortization": 1, + "wireFeeLimit": zero, + "prevPayCoins": [], + "wireMethod": "x-taler-bank" + }, + createCandidates([{ + amount: "LOCAL:10", + numAvailable: 5, + depositFee: "LOCAL:0.1", + fromExchange: "http://exchange.localhost/", + }]), + {"http://exchange.localhost/": exchangeWireFee}, + tally + ); + + expect(t, coins).deep.equal({ + "hash0;32;http://exchange.localhost/": { + exchangeBaseUrl: "http://exchange.localhost/", + denomPubHash: "hash0", + maxAge: 32, + contributions: [ + Amounts.parseOrThrow("LOCAL:2.2"), + ], + } + }); + + expect(t, tally).deep.equal({ + amountPayRemaining: Amounts.parseOrThrow("LOCAL:2"), + amountWireFeeLimitRemaining: zero, + amountDepositFeeLimitRemaining: zero, + customerDepositFees: zero, + customerWireFees: zero, + wireFeeCoveredForExchange: new Set(), + lastDepositFee: zero, + }); + +}); + @@ -179,3 +225,20 @@ function createCandidates(ar: {amount: AmountString, depositFee: AmountString, n } }) } + +type Tester = { + deep: { + equal(another: T): ReturnType; + equals(another: T): ReturnType; + } +} + +function expect(t: ExecutionContext, thing: T): Tester { + return { + deep: { + equal: (another: T) => t.deepEqual(thing, another), + equals: (another: T) => t.deepEqual(thing, another), + }, + }; +} + diff --git a/packages/taler-wallet-core/src/util/coinSelection.ts b/packages/taler-wallet-core/src/util/coinSelection.ts index 0885215dd..0b1be881f 100644 --- a/packages/taler-wallet-core/src/util/coinSelection.ts +++ b/packages/taler-wallet-core/src/util/coinSelection.ts @@ -419,6 +419,9 @@ interface SelResult { }; } +export function testing_selectGreedy(...args: Parameters): ReturnType{ + return selectGreedy(...args) +} function selectGreedy( req: SelectPayCoinRequestNg, candidateDenoms: AvailableDenom[], @@ -930,7 +933,7 @@ function greedySelectPeer( ).amount; tally.lastDepositFee = Amounts.parseOrThrow(denom.feeDeposit); - + contributions.push(coinSpend); } if (contributions.length > 0) { -- cgit v1.2.3 From f4587c44fd6a6d76384cd671550890255c3fe650 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 13 Sep 2023 16:08:51 +0200 Subject: wallet-core: use typed microsecond timestamps in DB --- packages/taler-util/src/time.ts | 4 + packages/taler-wallet-core/src/db.ts | 118 ++++++++++++++------- .../taler-wallet-core/src/operations/attention.ts | 3 +- .../src/operations/backup/index.ts | 31 ++++-- .../taler-wallet-core/src/operations/deposits.ts | 9 +- .../taler-wallet-core/src/operations/exchanges.ts | 7 +- .../src/operations/pay-merchant.ts | 15 +-- .../src/operations/pay-peer-pull-credit.ts | 27 +++-- .../src/operations/pay-peer-pull-debit.ts | 3 +- .../src/operations/pay-peer-push-credit.ts | 46 +++----- .../src/operations/pay-peer-push-debit.ts | 3 +- .../taler-wallet-core/src/operations/pending.ts | 3 +- .../taler-wallet-core/src/operations/recoup.ts | 5 +- .../taler-wallet-core/src/operations/refresh.ts | 11 +- .../taler-wallet-core/src/operations/reward.ts | 10 +- .../src/operations/transactions.ts | 35 +++--- .../taler-wallet-core/src/operations/withdraw.ts | 29 +++-- 17 files changed, 216 insertions(+), 143 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-util/src/time.ts b/packages/taler-util/src/time.ts index 46ed37637..a63f9b296 100644 --- a/packages/taler-util/src/time.ts +++ b/packages/taler-util/src/time.ts @@ -52,6 +52,10 @@ export interface TalerProtocolTimestamp { readonly _flavor?: typeof flavor_TalerProtocolTimestamp; } +/** + * Precise timestamp, typically used in the wallet-core + * API but not in other Taler APIs so far. + */ export interface TalerPreciseTimestamp { /** * Seconds (as integer) since epoch. diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 9bf9a29cc..cebe3635b 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -28,7 +28,6 @@ import { } from "@gnu-taler/idb-bridge"; import { AgeCommitmentProof, - AmountJson, AmountString, Amounts, AttentionInfo, @@ -45,12 +44,8 @@ import { ExchangeAuditor, ExchangeGlobalFees, HashCodeString, - InternationalizedString, Logger, - MerchantContractTerms, - MerchantInfo, PayCoinSelection, - PeerContractTerms, RefreshReason, TalerErrorDetail, TalerPreciseTimestamp, @@ -151,6 +146,53 @@ export const CURRENT_DB_CONFIG_KEY = "currentMainDbName"; */ export const WALLET_DB_MINOR_VERSION = 1; +declare const symDbProtocolTimestamp: unique symbol; + +declare const symDbPreciseTimestamp: unique symbol; + +/** + * Timestamp, stored as microseconds. + * + * Always rounded to a full second. + */ +export type DbProtocolTimestamp = number & { [symDbProtocolTimestamp]: true }; + +/** + * Timestamp, stored as microseconds. + */ +export type DbPreciseTimestamp = number & { [symDbPreciseTimestamp]: true }; + +const DB_TIMESTAMP_FOREVER = Number.MAX_SAFE_INTEGER; + +export function timestampPreciseFromDb( + dbTs: DbPreciseTimestamp, +): TalerPreciseTimestamp { + return TalerPreciseTimestamp.fromMilliseconds(Math.floor(dbTs / 1000)); +} + +export function timestampOptionalPreciseFromDb( + dbTs: DbPreciseTimestamp | undefined, +): TalerPreciseTimestamp | undefined { + if (!dbTs) { + return undefined; + } + return TalerPreciseTimestamp.fromMilliseconds(Math.floor(dbTs / 1000)); +} + +export function timestampPreciseToDb( + stamp: TalerPreciseTimestamp, +): DbPreciseTimestamp { + if (stamp.t_s === "never") { + return DB_TIMESTAMP_FOREVER as DbPreciseTimestamp; + } else { + let tUs = stamp.t_s * 1000000; + if (stamp.off_us) { + tUs == stamp.off_us; + } + return tUs as DbPreciseTimestamp; + } +} + /** * Format of the operation status code: 0x0abc_nnnn @@ -217,7 +259,7 @@ export enum WithdrawalGroupStatus { * Exchange is doing AML checks. */ PendingAml = 0x0100_0006, - SuspendedAml = 0x0100_0006, + SuspendedAml = 0x0110_0006, /** * The corresponding withdraw record has been created. @@ -268,14 +310,14 @@ export interface ReserveBankInfo { * * Set to undefined if that hasn't happened yet. */ - timestampReserveInfoPosted: TalerPreciseTimestamp | undefined; + timestampReserveInfoPosted: DbPreciseTimestamp | undefined; /** * Time when the reserve was confirmed by the bank. * * Set to undefined if not confirmed yet. */ - timestampBankConfirmed: TalerPreciseTimestamp | undefined; + timestampBankConfirmed: DbPreciseTimestamp | undefined; } /** @@ -488,7 +530,7 @@ export interface ExchangeDetailsRecord { tosAccepted: | { etag: string; - timestamp: TalerPreciseTimestamp; + timestamp: DbPreciseTimestamp; } | undefined; @@ -528,7 +570,7 @@ export interface ExchangeDetailsPointer { * Timestamp when the (masterPublicKey, currency) pointer * has been updated. */ - updateClock: TalerPreciseTimestamp; + updateClock: DbPreciseTimestamp; } export enum ExchangeEntryDbRecordStatus { @@ -567,7 +609,7 @@ export interface ExchangeEntryRecord { * * Used mostly in the UI to suggest exchanges. */ - lastWithdrawal?: TalerPreciseTimestamp; + lastWithdrawal?: DbPreciseTimestamp; /** * Pointer to the current exchange details. @@ -588,7 +630,7 @@ export interface ExchangeEntryRecord { /** * Last time when the exchange /keys info was updated. */ - lastUpdate: TalerPreciseTimestamp | undefined; + lastUpdate: DbPreciseTimestamp | undefined; /** * Next scheduled update for the exchange. @@ -816,7 +858,7 @@ export interface RewardRecord { * Has the user accepted the tip? Only after the tip has been accepted coins * withdrawn from the tip may be used. */ - acceptedTimestamp: TalerPreciseTimestamp | undefined; + acceptedTimestamp: DbPreciseTimestamp | undefined; /** * The tipped amount. @@ -869,7 +911,7 @@ export interface RewardRecord { */ merchantRewardId: string; - createdTimestamp: TalerPreciseTimestamp; + createdTimestamp: DbPreciseTimestamp; /** * The url to be redirected after the tip is accepted. @@ -880,7 +922,7 @@ export interface RewardRecord { * Timestamp for when the wallet finished picking up the tip * from the merchant. */ - pickedUpTimestamp: TalerPreciseTimestamp | undefined; + pickedUpTimestamp: DbPreciseTimestamp | undefined; status: RewardRecordStatus; } @@ -978,12 +1020,12 @@ export interface RefreshGroupRecord { */ statusPerCoin: RefreshCoinStatus[]; - timestampCreated: TalerPreciseTimestamp; + timestampCreated: DbPreciseTimestamp; /** * Timestamp when the refresh session finished. */ - timestampFinished: TalerPreciseTimestamp | undefined; + timestampFinished: DbPreciseTimestamp | undefined; } /** @@ -1208,7 +1250,7 @@ export interface PurchaseRecord { * Timestamp of the first time that sending a payment to the merchant * for this purchase was successful. */ - timestampFirstSuccessfulPay: TalerPreciseTimestamp | undefined; + timestampFirstSuccessfulPay: DbPreciseTimestamp | undefined; merchantPaySig: string | undefined; @@ -1223,19 +1265,19 @@ export interface PurchaseRecord { /** * When was the purchase record created? */ - timestamp: TalerPreciseTimestamp; + timestamp: DbPreciseTimestamp; /** * When was the purchase made? * Refers to the time that the user accepted. */ - timestampAccept: TalerPreciseTimestamp | undefined; + timestampAccept: DbPreciseTimestamp | undefined; /** * When was the last refund made? * Set to 0 if no refund was made on the purchase. */ - timestampLastRefundStatus: TalerPreciseTimestamp | undefined; + timestampLastRefundStatus: DbPreciseTimestamp | undefined; /** * Last session signature that we submitted to /pay (if any). @@ -1285,12 +1327,12 @@ export interface WalletBackupConfState { /** * Timestamp stored in the last backup. */ - lastBackupTimestamp?: TalerPreciseTimestamp; + lastBackupTimestamp?: DbPreciseTimestamp; /** * Last time we tried to do a backup. */ - lastBackupCheckTimestamp?: TalerPreciseTimestamp; + lastBackupCheckTimestamp?: DbPreciseTimestamp; lastBackupNonce?: string; } @@ -1398,12 +1440,12 @@ export interface WithdrawalGroupRecord { * When was the withdrawal operation started started? * Timestamp in milliseconds. */ - timestampStart: TalerPreciseTimestamp; + timestampStart: DbPreciseTimestamp; /** * When was the withdrawal operation completed? */ - timestampFinish?: TalerPreciseTimestamp; + timestampFinish?: DbPreciseTimestamp; /** * Current status of the reserve. @@ -1494,9 +1536,9 @@ export interface RecoupGroupRecord { exchangeBaseUrl: string; - timestampStarted: TalerPreciseTimestamp; + timestampStarted: DbPreciseTimestamp; - timestampFinished: TalerPreciseTimestamp | undefined; + timestampFinished: DbPreciseTimestamp | undefined; /** * Public keys that identify the coins being recouped @@ -1530,7 +1572,7 @@ export type BackupProviderState = } | { tag: BackupProviderStateTag.Ready; - nextBackupTimestamp: TalerPreciseTimestamp; + nextBackupTimestamp: DbPreciseTimestamp; } | { tag: BackupProviderStateTag.Retrying; @@ -1575,7 +1617,7 @@ export interface BackupProviderRecord { * Does NOT correspond to the timestamp of the backup, * which only changes when the backup content changes. */ - lastBackupCycleTimestamp?: TalerPreciseTimestamp; + lastBackupCycleTimestamp?: DbPreciseTimestamp; /** * Proposal that we're currently trying to pay for. @@ -1678,9 +1720,9 @@ export interface DepositGroupRecord { */ counterpartyEffectiveDepositAmount: AmountString; - timestampCreated: TalerPreciseTimestamp; + timestampCreated: DbPreciseTimestamp; - timestampFinished: TalerPreciseTimestamp | undefined; + timestampFinished: DbPreciseTimestamp | undefined; operationStatus: DepositOperationStatus; @@ -1791,7 +1833,7 @@ export interface PeerPushDebitRecord { purseExpiration: TalerProtocolTimestamp; - timestampCreated: TalerPreciseTimestamp; + timestampCreated: DbPreciseTimestamp; abortRefreshGroupId?: string; @@ -1864,7 +1906,7 @@ export interface PeerPullCreditRecord { contractEncNonce: string; - mergeTimestamp: TalerPreciseTimestamp; + mergeTimestamp: DbPreciseTimestamp; mergeReserveRowId: number; @@ -1916,7 +1958,7 @@ export interface PeerPushPaymentIncomingRecord { contractPriv: string; - timestamp: TalerPreciseTimestamp; + timestamp: DbPreciseTimestamp; estimatedAmountEffective: AmountString; @@ -1988,7 +2030,7 @@ export interface PeerPullPaymentIncomingRecord { contractTermsHash: string; - timestampCreated: TalerPreciseTimestamp; + timestampCreated: DbPreciseTimestamp; /** * Contract priv that we got from the other party. @@ -2095,7 +2137,7 @@ export interface UserAttentionRecord { /** * When the user mark this notification as read. */ - read: TalerPreciseTimestamp | undefined; + read: DbPreciseTimestamp | undefined; } export interface DbExchangeHandle { @@ -2139,7 +2181,7 @@ export interface RefundGroupRecord { /** * Timestamp when the refund group was created. */ - timestampCreated: TalerPreciseTimestamp; + timestampCreated: DbPreciseTimestamp; proposalId: string; @@ -2196,7 +2238,7 @@ export interface RefundItemRecord { /** * Time when the wallet became aware of the refund. */ - obtainedTime: TalerPreciseTimestamp; + obtainedTime: DbPreciseTimestamp; refundAmount: AmountString; diff --git a/packages/taler-wallet-core/src/operations/attention.ts b/packages/taler-wallet-core/src/operations/attention.ts index 7d84b43ef..1030db0a6 100644 --- a/packages/taler-wallet-core/src/operations/attention.ts +++ b/packages/taler-wallet-core/src/operations/attention.ts @@ -31,6 +31,7 @@ import { UserAttentionUnreadList, } from "@gnu-taler/taler-util"; import { InternalWalletState } from "../internal-wallet-state.js"; +import { timestampPreciseToDb } from "../index.js"; const logger = new Logger("operations/attention.ts"); @@ -94,7 +95,7 @@ export async function markAttentionRequestAsRead( if (!ua) throw Error("attention request not found"); tx.userAttention.put({ ...ua, - read: TalerPreciseTimestamp.now(), + read: timestampPreciseToDb(TalerPreciseTimestamp.now()), }); }); } diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts b/packages/taler-wallet-core/src/operations/backup/index.ts index a5e8dbd42..7a2771c57 100644 --- a/packages/taler-wallet-core/src/operations/backup/index.ts +++ b/packages/taler-wallet-core/src/operations/backup/index.ts @@ -84,6 +84,9 @@ import { ConfigRecord, ConfigRecordKey, WalletBackupConfState, + timestampOptionalPreciseFromDb, + timestampPreciseFromDb, + timestampPreciseToDb, } from "../../db.js"; import { InternalWalletState } from "../../internal-wallet-state.js"; import { assertUnreachable } from "../../util/assertUnreachable.js"; @@ -259,10 +262,12 @@ async function runBackupCycleForProvider( if (!prov) { return; } - prov.lastBackupCycleTimestamp = TalerPreciseTimestamp.now(); + prov.lastBackupCycleTimestamp = timestampPreciseToDb( + TalerPreciseTimestamp.now(), + ); prov.state = { tag: BackupProviderStateTag.Ready, - nextBackupTimestamp: getNextBackupTimestamp(), + nextBackupTimestamp: timestampPreciseToDb(getNextBackupTimestamp()), }; await tx.backupProviders.put(prov); }); @@ -361,10 +366,12 @@ async function runBackupCycleForProvider( return; } prov.lastBackupHash = encodeCrock(currentBackupHash); - prov.lastBackupCycleTimestamp = TalerPreciseTimestamp.now(); + prov.lastBackupCycleTimestamp = timestampPreciseToDb( + TalerPreciseTimestamp.now(), + ); prov.state = { tag: BackupProviderStateTag.Ready, - nextBackupTimestamp: getNextBackupTimestamp(), + nextBackupTimestamp: timestampPreciseToDb(getNextBackupTimestamp()), }; await tx.backupProviders.put(prov); }); @@ -594,7 +601,9 @@ export async function addBackupProvider( if (req.activate) { oldProv.state = { tag: BackupProviderStateTag.Ready, - nextBackupTimestamp: TalerPreciseTimestamp.now(), + nextBackupTimestamp: timestampPreciseToDb( + TalerPreciseTimestamp.now(), + ), }; logger.info("setting existing backup provider to active"); await tx.backupProviders.put(oldProv); @@ -616,7 +625,9 @@ export async function addBackupProvider( if (req.activate) { state = { tag: BackupProviderStateTag.Ready, - nextBackupTimestamp: TalerPreciseTimestamp.now(), + nextBackupTimestamp: timestampPreciseToDb( + TalerPreciseTimestamp.now(), + ), }; } else { state = { @@ -840,7 +851,9 @@ export async function getBackupInfo( providers.push({ active: x.provider.state.tag !== BackupProviderStateTag.Provisional, syncProviderBaseUrl: x.provider.baseUrl, - lastSuccessfulBackupTimestamp: x.provider.lastBackupCycleTimestamp, + lastSuccessfulBackupTimestamp: timestampOptionalPreciseFromDb( + x.provider.lastBackupCycleTimestamp, + ), paymentProposalIds: x.provider.paymentProposalIds, lastError: x.provider.state.tag === BackupProviderStateTag.Retrying @@ -917,7 +930,9 @@ async function backupRecoveryTheirs( shouldRetryFreshProposal: false, state: { tag: BackupProviderStateTag.Ready, - nextBackupTimestamp: TalerPreciseTimestamp.now(), + nextBackupTimestamp: timestampPreciseToDb( + TalerPreciseTimestamp.now(), + ), }, uids: [encodeCrock(getRandomBytes(32))], }); diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts index 2de8f30a1..cb40f8f22 100644 --- a/packages/taler-wallet-core/src/operations/deposits.ts +++ b/packages/taler-wallet-core/src/operations/deposits.ts @@ -73,6 +73,7 @@ import { RefreshOperationStatus, createRefreshGroup, getTotalRefreshCost, + timestampPreciseToDb, } from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; import { assertUnreachable } from "../util/assertUnreachable.js"; @@ -857,7 +858,9 @@ async function processDepositGroupPendingTrack( } } if (allWired) { - dg.timestampFinished = TalerPreciseTimestamp.now(); + dg.timestampFinished = timestampPreciseToDb( + TalerPreciseTimestamp.now(), + ); dg.operationStatus = DepositOperationStatus.Finished; await tx.depositGroups.put(dg); } @@ -1375,7 +1378,9 @@ export async function createDepositGroup( amount: contractData.amount, noncePriv: noncePair.priv, noncePub: noncePair.pub, - timestampCreated: AbsoluteTime.toPreciseTimestamp(now), + timestampCreated: timestampPreciseToDb( + AbsoluteTime.toPreciseTimestamp(now), + ), timestampFinished: undefined, statusPerCoin: payCoinSel.coinSel.coinPubs.map( () => DepositElementStatus.DepositPending, diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts index 43a08ed3b..60d55252a 100644 --- a/packages/taler-wallet-core/src/operations/exchanges.ts +++ b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -74,6 +74,7 @@ import { ExchangeEntryDbRecordStatus, ExchangeEntryDbUpdateStatus, isWithdrawableDenom, + timestampPreciseToDb, WalletDbReadWriteTransaction, } from "../index.js"; import { InternalWalletState, TrustInfo } from "../internal-wallet-state.js"; @@ -174,7 +175,7 @@ export async function acceptExchangeTermsOfService( if (d) { d.tosAccepted = { etag: etag || d.tosCurrentEtag, - timestamp: TalerPreciseTimestamp.now(), + timestamp: timestampPreciseToDb(TalerPreciseTimestamp.now()), }; await tx.exchangeDetails.put(d); } @@ -753,7 +754,7 @@ export async function updateExchangeFromUrlHandler( if (existingDetails?.rowId) { newDetails.rowId = existingDetails.rowId; } - r.lastUpdate = TalerPreciseTimestamp.now(); + r.lastUpdate = timestampPreciseToDb(TalerPreciseTimestamp.now()); r.nextUpdateStampMs = AbsoluteTime.toStampMs( AbsoluteTime.fromProtocolTimestamp(keysInfo.expiry), ); @@ -763,7 +764,7 @@ export async function updateExchangeFromUrlHandler( r.detailsPointer = { currency: newDetails.currency, masterPublicKey: newDetails.masterPublicKey, - updateClock: TalerPreciseTimestamp.now(), + updateClock: timestampPreciseToDb(TalerPreciseTimestamp.now()), }; } await tx.exchanges.put(r); diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts index fe0cbeda0..97bf6e2a6 100644 --- a/packages/taler-wallet-core/src/operations/pay-merchant.ts +++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts @@ -103,6 +103,7 @@ import { RefundGroupStatus, RefundItemRecord, RefundItemStatus, + timestampPreciseToDb, } from "../index.js"; import { EXCHANGE_COINS_LOCK, @@ -644,7 +645,7 @@ async function createPurchase( noncePriv: priv, noncePub: pub, claimToken, - timestamp: TalerPreciseTimestamp.now(), + timestamp: timestampPreciseToDb(TalerPreciseTimestamp.now()), merchantBaseUrl, orderId, proposalId: proposalId, @@ -717,7 +718,7 @@ async function storeFirstPaySuccess( if (purchase.purchaseStatus === PurchaseStatus.PendingPaying) { purchase.purchaseStatus = PurchaseStatus.Done; } - purchase.timestampFirstSuccessfulPay = now; + purchase.timestampFirstSuccessfulPay = timestampPreciseToDb(now); purchase.lastSessionId = sessionId; purchase.merchantPaySig = payResponse.sig; purchase.posConfirmation = payResponse.pos_confirmation; @@ -941,7 +942,9 @@ async function unblockBackup( .forEachAsync(async (bp) => { bp.state = { tag: BackupProviderStateTag.Ready, - nextBackupTimestamp: TalerPreciseTimestamp.now(), + nextBackupTimestamp: timestampPreciseToDb( + TalerPreciseTimestamp.now(), + ), }; tx.backupProviders.put(bp); }); @@ -1447,7 +1450,7 @@ export async function confirmPay( totalPayCost: Amounts.stringify(payCostInfo), }; p.lastSessionId = sessionId; - p.timestampAccept = TalerPreciseTimestamp.now(); + p.timestampAccept = timestampPreciseToDb(TalerPreciseTimestamp.now()); p.purchaseStatus = PurchaseStatus.PendingPaying; await tx.purchases.put(p); await spendCoins(ws, tx, { @@ -2791,7 +2794,7 @@ async function storeRefunds( proposalId: purchase.proposalId, refundGroupId: newRefundGroupId, status: RefundGroupStatus.Pending, - timestampCreated: now, + timestampCreated: timestampPreciseToDb(now), amountEffective: Amounts.stringify( Amounts.zeroOfCurrency(currency), ), @@ -2802,7 +2805,7 @@ async function storeRefunds( const newItem: RefundItemRecord = { coinPub: rf.coin_pub, executionTime: rf.execution_time, - obtainedTime: now, + obtainedTime: timestampPreciseToDb(now), refundAmount: rf.refund_amount, refundGroupId: newGroup.refundGroupId, rtxid: rf.rtransaction_id, diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts index 0355eb152..6ec8822ab 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts @@ -60,6 +60,9 @@ import { PeerPullPaymentCreditStatus, WithdrawalGroupStatus, WithdrawalRecordType, + timestampOptionalPreciseFromDb, + timestampPreciseFromDb, + timestampPreciseToDb, updateExchangeFromUrl, } from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; @@ -395,12 +398,14 @@ async function handlePeerPullCreditCreatePurse( nonce: pullIni.contractEncNonce, }); + const mergeTimestamp = timestampPreciseFromDb(pullIni.mergeTimestamp); + const purseExpiration = contractTerms.purse_expiration; const sigRes = await ws.cryptoApi.signReservePurseCreate({ contractTermsHash: pullIni.contractTermsHash, flags: WalletAccountMergeFlags.CreateWithPurseFee, mergePriv: pullIni.mergePriv, - mergeTimestamp: TalerPreciseTimestamp.round(pullIni.mergeTimestamp), + mergeTimestamp: TalerPreciseTimestamp.round(mergeTimestamp), purseAmount: pullIni.amount, purseExpiration: purseExpiration, purseFee: purseFee, @@ -412,7 +417,7 @@ async function handlePeerPullCreditCreatePurse( const reservePurseReqBody: ExchangeReservePurseRequest = { merge_sig: sigRes.mergeSig, - merge_timestamp: TalerPreciseTimestamp.round(pullIni.mergeTimestamp), + merge_timestamp: TalerPreciseTimestamp.round(mergeTimestamp), h_contract_terms: pullIni.contractTermsHash, merge_pub: pullIni.mergePub, min_age: 0, @@ -695,11 +700,17 @@ async function getPreferredExchangeForCurrency( if (candidate.lastWithdrawal && !e.lastWithdrawal) { continue; } - if (candidate.lastWithdrawal && e.lastWithdrawal) { + const exchangeLastWithdrawal = timestampOptionalPreciseFromDb( + e.lastWithdrawal, + ); + const candidateLastWithdrawal = timestampOptionalPreciseFromDb( + candidate.lastWithdrawal, + ); + if (exchangeLastWithdrawal && candidateLastWithdrawal) { if ( AbsoluteTime.cmp( - AbsoluteTime.fromPreciseTimestamp(e.lastWithdrawal), - AbsoluteTime.fromPreciseTimestamp(candidate.lastWithdrawal), + AbsoluteTime.fromPreciseTimestamp(exchangeLastWithdrawal), + AbsoluteTime.fromPreciseTimestamp(candidateLastWithdrawal), ) > 0 ) { candidate = e; @@ -741,8 +752,6 @@ export async function initiatePeerPullPayment( exchangeBaseUrl: exchangeBaseUrl, }); - const mergeTimestamp = TalerPreciseTimestamp.now(); - const pursePair = await ws.cryptoApi.createEddsaKeypair({}); const mergePair = await ws.cryptoApi.createEddsaKeypair({}); @@ -766,6 +775,8 @@ export async function initiatePeerPullPayment( undefined, ); + const mergeTimestamp = TalerPreciseTimestamp.now(); + const transitionInfo = await ws.db .mktx((x) => [x.peerPullCredit, x.contractTerms]) .runReadWrite(async (tx) => { @@ -778,7 +789,7 @@ export async function initiatePeerPullPayment( mergePriv: mergePair.priv, mergePub: mergePair.pub, status: PeerPullPaymentCreditStatus.PendingCreatePurse, - mergeTimestamp, + mergeTimestamp: timestampPreciseToDb(mergeTimestamp), contractEncNonce, mergeReserveRowId: mergeReserveRowId, contractPriv: contractKeyPair.priv, diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts index 5bcfa3418..48cbf574f 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-debit.ts @@ -59,6 +59,7 @@ import { PendingTaskType, RefreshOperationStatus, createRefreshGroup, + timestampPreciseToDb, } from "../index.js"; import { assertUnreachable } from "../util/assertUnreachable.js"; import { checkLogicInvariant } from "../util/invariants.js"; @@ -595,7 +596,7 @@ export async function preparePeerPullDebit( contractPriv: contractPriv, exchangeBaseUrl: exchangeBaseUrl, pursePub: pursePub, - timestampCreated: TalerPreciseTimestamp.now(), + timestampCreated: timestampPreciseToDb(TalerPreciseTimestamp.now()), contractTermsHash, amount: contractTerms.amount, status: PeerPullDebitRecordStatus.DialogProposed, diff --git a/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts b/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts index 89d9e3b49..e4698c203 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer-push-credit.ts @@ -59,6 +59,7 @@ import { PendingTaskType, WithdrawalGroupStatus, WithdrawalRecordType, + timestampPreciseToDb, } from "../index.js"; import { assertUnreachable } from "../util/assertUnreachable.js"; import { checkDbInvariant } from "../util/invariants.js"; @@ -129,12 +130,10 @@ export async function preparePeerPushCredit( amountEffective: existing.existingPushInc.estimatedAmountEffective, amountRaw: existing.existingContractTerms.amount, contractTerms: existing.existingContractTerms, - peerPushCreditId: - existing.existingPushInc.peerPushCreditId, + peerPushCreditId: existing.existingPushInc.peerPushCreditId, transactionId: constructTransactionIdentifier({ tag: TransactionType.PeerPushCredit, - peerPushCreditId: - existing.existingPushInc.peerPushCreditId, + peerPushCreditId: existing.existingPushInc.peerPushCreditId, }), }; } @@ -196,7 +195,7 @@ export async function preparePeerPushCredit( exchangeBaseUrl: exchangeBaseUrl, mergePriv: dec.mergePriv, pursePub: pursePub, - timestamp: TalerPreciseTimestamp.now(), + timestamp: timestampPreciseToDb(TalerPreciseTimestamp.now()), contractTermsHash, status: PeerPushCreditStatus.DialogProposed, withdrawalGroupId, @@ -263,16 +262,11 @@ async function longpollKycStatus( const transitionInfo = await ws.db .mktx((x) => [x.peerPushCredit]) .runReadWrite(async (tx) => { - const peerInc = await tx.peerPushCredit.get( - peerPushCreditId, - ); + const peerInc = await tx.peerPushCredit.get(peerPushCreditId); if (!peerInc) { return; } - if ( - peerInc.status !== - PeerPushCreditStatus.PendingMergeKycRequired - ) { + if (peerInc.status !== PeerPushCreditStatus.PendingMergeKycRequired) { return; } const oldTxState = computePeerPushCreditTransactionState(peerInc); @@ -333,9 +327,7 @@ async function processPeerPushCreditKycRequired( const { transitionInfo, result } = await ws.db .mktx((x) => [x.peerPushCredit]) .runReadWrite(async (tx) => { - const peerInc = await tx.peerPushCredit.get( - peerPushCreditId, - ); + const peerInc = await tx.peerPushCredit.get(peerPushCreditId); if (!peerInc) { return { transitionInfo: undefined, @@ -466,9 +458,7 @@ async function handlePendingMerge( x.exchangeDetails, ]) .runReadWrite(async (tx) => { - const peerInc = await tx.peerPushCredit.get( - peerPushCreditId, - ); + const peerInc = await tx.peerPushCredit.get(peerPushCreditId); if (!peerInc) { return undefined; } @@ -520,9 +510,7 @@ async function handlePendingWithdrawing( const transitionInfo = await ws.db .mktx((x) => [x.peerPushCredit, x.withdrawalGroups]) .runReadWrite(async (tx) => { - const ppi = await tx.peerPushCredit.get( - peerInc.peerPushCreditId, - ); + const ppi = await tx.peerPushCredit.get(peerInc.peerPushCreditId); if (!ppi) { finished = true; return; @@ -631,9 +619,7 @@ export async function confirmPeerPushCredit( } peerPushCreditId = parsedTx.peerPushCreditId; } else { - throw Error( - "no transaction ID (or deprecated peerPushCreditId) provided", - ); + throw Error("no transaction ID (or deprecated peerPushCreditId) provided"); } await ws.db @@ -683,9 +669,7 @@ export async function suspendPeerPushCreditTransaction( const transitionInfo = await ws.db .mktx((x) => [x.peerPushCredit]) .runReadWrite(async (tx) => { - const pushCreditRec = await tx.peerPushCredit.get( - peerPushCreditId, - ); + const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId); if (!pushCreditRec) { logger.warn(`peer push credit ${peerPushCreditId} not found`); return; @@ -746,9 +730,7 @@ export async function abortPeerPushCreditTransaction( const transitionInfo = await ws.db .mktx((x) => [x.peerPushCredit]) .runReadWrite(async (tx) => { - const pushCreditRec = await tx.peerPushCredit.get( - peerPushCreditId, - ); + const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId); if (!pushCreditRec) { logger.warn(`peer push credit ${peerPushCreditId} not found`); return; @@ -820,9 +802,7 @@ export async function resumePeerPushCreditTransaction( const transitionInfo = await ws.db .mktx((x) => [x.peerPushCredit]) .runReadWrite(async (tx) => { - const pushCreditRec = await tx.peerPushCredit.get( - peerPushCreditId, - ); + const pushCreditRec = await tx.peerPushCredit.get(peerPushCreditId); if (!pushCreditRec) { logger.warn(`peer push credit ${peerPushCreditId} not found`); return; diff --git a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts index e80ffc059..b3d0eb132 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts @@ -55,6 +55,7 @@ import { PeerPushDebitStatus, RefreshOperationStatus, createRefreshGroup, + timestampPreciseToDb, } from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; import { PendingTaskType } from "../pending-types.js"; @@ -669,7 +670,7 @@ export async function initiatePeerPushDebit( purseExpiration: purseExpiration, pursePriv: pursePair.priv, pursePub: pursePair.pub, - timestampCreated: TalerPreciseTimestamp.now(), + timestampCreated: timestampPreciseToDb(TalerPreciseTimestamp.now()), status: PeerPushDebitStatus.PendingCreatePurse, contractEncNonce, coinSel: { diff --git a/packages/taler-wallet-core/src/operations/pending.ts b/packages/taler-wallet-core/src/operations/pending.ts index 6115f848b..120d316ce 100644 --- a/packages/taler-wallet-core/src/operations/pending.ts +++ b/packages/taler-wallet-core/src/operations/pending.ts @@ -47,6 +47,7 @@ import { ExchangeEntryDbUpdateStatus, RefreshOperationStatus, DepositElementStatus, + timestampPreciseFromDb, } from "../db.js"; import { PendingOperationsResponse, @@ -445,7 +446,7 @@ async function gatherBackupPending( const retryRecord = await tx.operationRetries.get(opId); if (bp.state.tag === BackupProviderStateTag.Ready) { const timestampDue = AbsoluteTime.fromPreciseTimestamp( - bp.state.nextBackupTimestamp, + timestampPreciseFromDb(bp.state.nextBackupTimestamp), ); resp.pendingOperations.push({ type: PendingTaskType.Backup, diff --git a/packages/taler-wallet-core/src/operations/recoup.ts b/packages/taler-wallet-core/src/operations/recoup.ts index 6a18e5de6..782e98d1c 100644 --- a/packages/taler-wallet-core/src/operations/recoup.ts +++ b/packages/taler-wallet-core/src/operations/recoup.ts @@ -47,6 +47,7 @@ import { WithdrawCoinSource, WithdrawalGroupStatus, WithdrawalRecordType, + timestampPreciseToDb, } from "../db.js"; import { InternalWalletState } from "../internal-wallet-state.js"; import { checkDbInvariant } from "../util/invariants.js"; @@ -391,7 +392,7 @@ export async function processRecoupGroup( if (!rg2) { return; } - rg2.timestampFinished = TalerPreciseTimestamp.now(); + rg2.timestampFinished = timestampPreciseToDb(TalerPreciseTimestamp.now()); if (rg2.scheduleRefreshCoins.length > 0) { const refreshGroupId = await createRefreshGroup( ws, @@ -424,7 +425,7 @@ export async function createRecoupGroup( exchangeBaseUrl: exchangeBaseUrl, coinPubs: coinPubs, timestampFinished: undefined, - timestampStarted: TalerPreciseTimestamp.now(), + timestampStarted: timestampPreciseToDb(TalerPreciseTimestamp.now()), recoupFinishedPerCoin: coinPubs.map(() => false), scheduleRefreshCoins: [], }; diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts index 75adbc860..dc1d53627 100644 --- a/packages/taler-wallet-core/src/operations/refresh.ts +++ b/packages/taler-wallet-core/src/operations/refresh.ts @@ -80,6 +80,7 @@ import { isWithdrawableDenom, PendingTaskType, RefreshSessionRecord, + timestampPreciseToDb, } from "../index.js"; import { EXCHANGE_COINS_LOCK, @@ -157,10 +158,10 @@ function updateGroupStatus(rg: RefreshGroupRecord): { final: boolean } { ); if (allFinal) { if (anyFailed) { - rg.timestampFinished = TalerPreciseTimestamp.now(); + rg.timestampFinished = timestampPreciseToDb(TalerPreciseTimestamp.now()); rg.operationStatus = RefreshOperationStatus.Failed; } else { - rg.timestampFinished = TalerPreciseTimestamp.now(); + rg.timestampFinished = timestampPreciseToDb(TalerPreciseTimestamp.now()); rg.operationStatus = RefreshOperationStatus.Finished; } return { final: true }; @@ -1099,12 +1100,14 @@ export async function createRefreshGroup( expectedOutputPerCoin: estimatedOutputPerCoin.map((x) => Amounts.stringify(x), ), - timestampCreated: TalerPreciseTimestamp.now(), + timestampCreated: timestampPreciseToDb(TalerPreciseTimestamp.now()), }; if (oldCoinPubs.length == 0) { logger.warn("created refresh group with zero coins"); - refreshGroup.timestampFinished = TalerPreciseTimestamp.now(); + refreshGroup.timestampFinished = timestampPreciseToDb( + TalerPreciseTimestamp.now(), + ); refreshGroup.operationStatus = RefreshOperationStatus.Finished; } diff --git a/packages/taler-wallet-core/src/operations/reward.ts b/packages/taler-wallet-core/src/operations/reward.ts index 6ae021174..3681dc4f5 100644 --- a/packages/taler-wallet-core/src/operations/reward.ts +++ b/packages/taler-wallet-core/src/operations/reward.ts @@ -50,6 +50,8 @@ import { DenominationRecord, RewardRecord, RewardRecordStatus, + timestampPreciseFromDb, + timestampPreciseToDb, } from "../db.js"; import { makeErrorDetail } from "@gnu-taler/taler-util"; import { InternalWalletState } from "../internal-wallet-state.js"; @@ -203,7 +205,7 @@ export async function prepareTip( exchangeBaseUrl: tipPickupStatus.exchange_url, next_url: tipPickupStatus.next_url, merchantBaseUrl: res.merchantBaseUrl, - createdTimestamp: TalerPreciseTimestamp.now(), + createdTimestamp: timestampPreciseToDb(TalerPreciseTimestamp.now()), merchantRewardId: res.merchantRewardId, rewardAmountEffective: Amounts.stringify(selectedDenoms.totalCoinValue), denomsSel: selectedDenoms, @@ -411,7 +413,7 @@ export async function processTip( return; } const oldTxState = computeRewardTransactionStatus(tr); - tr.pickedUpTimestamp = TalerPreciseTimestamp.now(); + tr.pickedUpTimestamp = timestampPreciseToDb(TalerPreciseTimestamp.now()); tr.status = RewardRecordStatus.Done; await tx.rewards.put(tr); const newTxState = computeRewardTransactionStatus(tr); @@ -448,7 +450,9 @@ export async function acceptTip( return { tipRecord }; } const oldTxState = computeRewardTransactionStatus(tipRecord); - tipRecord.acceptedTimestamp = TalerPreciseTimestamp.now(); + tipRecord.acceptedTimestamp = timestampPreciseToDb( + TalerPreciseTimestamp.now(), + ); tipRecord.status = RewardRecordStatus.PendingPickup; await tx.rewards.put(tipRecord); const newTxState = computeRewardTransactionStatus(tipRecord); diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts index d7b277faf..41bdae249 100644 --- a/packages/taler-wallet-core/src/operations/transactions.ts +++ b/packages/taler-wallet-core/src/operations/transactions.ts @@ -65,7 +65,12 @@ import { WithdrawalGroupStatus, WithdrawalRecordType, } from "../db.js"; -import { GetReadOnlyAccess, WalletStoresV1 } from "../index.js"; +import { + GetReadOnlyAccess, + timestampOptionalPreciseFromDb, + timestampPreciseFromDb, + WalletStoresV1, +} from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; import { PendingTaskType } from "../pending-types.js"; import { assertUnreachable } from "../util/assertUnreachable.js"; @@ -470,7 +475,7 @@ function buildTransactionForPushPaymentDebit( expiration: contractTerms.purse_expiration, summary: contractTerms.summary, }, - timestamp: pi.timestampCreated, + timestamp: timestampPreciseFromDb(pi.timestampCreated), talerUri: stringifyPayPushUri({ exchangeBaseUrl: pi.exchangeBaseUrl, contractPriv: pi.contractPriv, @@ -501,7 +506,7 @@ function buildTransactionForPullPaymentDebit( expiration: contractTerms.purse_expiration, summary: contractTerms.summary, }, - timestamp: pi.timestampCreated, + timestamp: timestampPreciseFromDb(pi.timestampCreated), transactionId: constructTransactionIdentifier({ tag: TransactionType.PeerPullDebit, peerPullDebitId: pi.peerPullDebitId, @@ -543,8 +548,7 @@ function buildTransactionForPeerPullCredit( amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue), amountRaw: Amounts.stringify(wsr.instructedAmount), exchangeBaseUrl: wsr.exchangeBaseUrl, - // Old transactions don't have it! - timestamp: pullCredit.mergeTimestamp ?? TalerPreciseTimestamp.now(), + timestamp: timestampPreciseFromDb(pullCredit.mergeTimestamp), info: { expiration: peerContractTerms.purse_expiration, summary: peerContractTerms.summary, @@ -575,8 +579,7 @@ function buildTransactionForPeerPullCredit( amountEffective: Amounts.stringify(pullCredit.estimatedAmountEffective), amountRaw: Amounts.stringify(peerContractTerms.amount), exchangeBaseUrl: pullCredit.exchangeBaseUrl, - // Old transactions don't have it! - timestamp: pullCredit.mergeTimestamp ?? TalerProtocolTimestamp.now(), + timestamp: timestampPreciseFromDb(pullCredit.mergeTimestamp), info: { expiration: peerContractTerms.purse_expiration, summary: peerContractTerms.summary, @@ -617,7 +620,7 @@ function buildTransactionForPeerPushCredit( expiration: peerContractTerms.purse_expiration, summary: peerContractTerms.summary, }, - timestamp: wsr.timestampStart, + timestamp: timestampPreciseFromDb(wsr.timestampStart), transactionId: constructTransactionIdentifier({ tag: TransactionType.PeerPushCredit, peerPushCreditId: pushInc.peerPushCreditId, @@ -640,7 +643,7 @@ function buildTransactionForPeerPushCredit( summary: peerContractTerms.summary, }, kycUrl: pushInc.kycUrl, - timestamp: pushInc.timestamp, + timestamp: timestampPreciseFromDb(pushInc.timestamp), transactionId: constructTransactionIdentifier({ tag: TransactionType.PeerPushCredit, peerPushCreditId: pushInc.peerPushCreditId, @@ -673,7 +676,7 @@ function buildTransactionForBankIntegratedWithdraw( }, kycUrl: wgRecord.kycUrl, exchangeBaseUrl: wgRecord.exchangeBaseUrl, - timestamp: wgRecord.timestampStart, + timestamp: timestampPreciseFromDb(wgRecord.timestampStart), transactionId: constructTransactionIdentifier({ tag: TransactionType.Withdrawal, withdrawalGroupId: wgRecord.withdrawalGroupId, @@ -717,7 +720,7 @@ function buildTransactionForManualWithdraw( }, kycUrl: withdrawalGroup.kycUrl, exchangeBaseUrl: withdrawalGroup.exchangeBaseUrl, - timestamp: withdrawalGroup.timestampStart, + timestamp: timestampPreciseFromDb(withdrawalGroup.timestampStart), transactionId: constructTransactionIdentifier({ tag: TransactionType.Withdrawal, withdrawalGroupId: withdrawalGroup.withdrawalGroupId, @@ -748,7 +751,7 @@ function buildTransactionForRefund( tag: TransactionType.Payment, proposalId: refundRecord.proposalId, }), - timestamp: refundRecord.timestampCreated, + timestamp: timestampPreciseFromDb(refundRecord.timestampCreated), transactionId: constructTransactionIdentifier({ tag: TransactionType.Refund, refundGroupId: refundRecord.refundGroupId, @@ -786,7 +789,7 @@ function buildTransactionForRefresh( refreshOutputAmount: Amounts.stringify(outputAmount), originatingTransactionId: refreshGroupRecord.reasonDetails?.originatingTransactionId, - timestamp: refreshGroupRecord.timestampCreated, + timestamp: timestampPreciseFromDb(refreshGroupRecord.timestampCreated), transactionId: constructTransactionIdentifier({ tag: TransactionType.Refresh, refreshGroupId: refreshGroupRecord.refreshGroupId, @@ -812,7 +815,7 @@ function buildTransactionForDeposit( txActions: computeDepositTransactionActions(dg), amountRaw: Amounts.stringify(dg.counterpartyEffectiveDepositAmount), amountEffective: Amounts.stringify(dg.totalPayCost), - timestamp: dg.timestampCreated, + timestamp: timestampPreciseFromDb(dg.timestampCreated), targetPaytoUri: dg.wire.payto_uri, wireTransferDeadline: dg.wireTransferDeadline, transactionId: constructTransactionIdentifier({ @@ -845,7 +848,7 @@ function buildTransactionForTip( txActions: computeTipTransactionActions(tipRecord), amountEffective: Amounts.stringify(tipRecord.rewardAmountEffective), amountRaw: Amounts.stringify(tipRecord.rewardAmountRaw), - timestamp: tipRecord.acceptedTimestamp, + timestamp: timestampPreciseFromDb(tipRecord.acceptedTimestamp), transactionId: constructTransactionIdentifier({ tag: TransactionType.Reward, walletRewardId: tipRecord.walletRewardId, @@ -922,7 +925,7 @@ async function buildTransactionForPurchase( : Amounts.stringify(purchaseRecord.refundAmountAwaiting), refunds, posConfirmation: purchaseRecord.posConfirmation, - timestamp, + timestamp: timestampPreciseFromDb(timestamp), transactionId: constructTransactionIdentifier({ tag: TransactionType.Payment, proposalId: purchaseRecord.proposalId, diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index 32e63f4f6..fb503d75f 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -131,6 +131,7 @@ import { ExchangeEntryDbUpdateStatus, PendingTaskType, isWithdrawableDenom, + timestampPreciseToDb, } from "../index.js"; import { TransitionInfo, @@ -1325,7 +1326,7 @@ async function processWithdrawalGroupAbortingBank( } const txStatusOld = computeWithdrawalTransactionStatus(wg); wg.status = WithdrawalGroupStatus.AbortedBank; - wg.timestampFinish = TalerPreciseTimestamp.now(); + wg.timestampFinish = timestampPreciseToDb(TalerPreciseTimestamp.now()); const txStatusNew = computeWithdrawalTransactionStatus(wg); await tx.withdrawalGroups.put(wg); return { @@ -1458,7 +1459,7 @@ async function processWithdrawalGroupPendingReady( } const txStatusOld = computeWithdrawalTransactionStatus(wg); wg.status = WithdrawalGroupStatus.Done; - wg.timestampFinish = TalerPreciseTimestamp.now(); + wg.timestampFinish = timestampPreciseToDb(TalerPreciseTimestamp.now()); const txStatusNew = computeWithdrawalTransactionStatus(wg); await tx.withdrawalGroups.put(wg); return { @@ -1554,7 +1555,7 @@ async function processWithdrawalGroupPendingReady( const oldTxState = computeWithdrawalTransactionStatus(wg); logger.info(`now withdrawn ${numFinished} of ${numTotalCoins} coins`); if (wg.timestampFinish === undefined && numFinished === numTotalCoins) { - wg.timestampFinish = TalerPreciseTimestamp.now(); + wg.timestampFinish = timestampPreciseToDb(TalerPreciseTimestamp.now()); wg.status = WithdrawalGroupStatus.Done; await makeCoinsVisible(ws, tx, transactionId); } @@ -2047,8 +2048,9 @@ async function registerReserveWithBank( if (r.wgInfo.withdrawalType !== WithdrawalRecordType.BankIntegrated) { throw Error("invariant failed"); } - r.wgInfo.bankInfo.timestampReserveInfoPosted = - AbsoluteTime.toPreciseTimestamp(AbsoluteTime.now()); + r.wgInfo.bankInfo.timestampReserveInfoPosted = timestampPreciseToDb( + AbsoluteTime.toPreciseTimestamp(AbsoluteTime.now()), + ); const oldTxState = computeWithdrawalTransactionStatus(r); r.status = WithdrawalGroupStatus.PendingWaitConfirmBank; const newTxState = computeWithdrawalTransactionStatus(r); @@ -2130,7 +2132,7 @@ async function processReserveBankStatus( } const now = AbsoluteTime.toPreciseTimestamp(AbsoluteTime.now()); const oldTxState = computeWithdrawalTransactionStatus(r); - r.wgInfo.bankInfo.timestampBankConfirmed = now; + r.wgInfo.bankInfo.timestampBankConfirmed = timestampPreciseToDb(now); r.status = WithdrawalGroupStatus.FailedBankAborted; const newTxState = computeWithdrawalTransactionStatus(r); await tx.withdrawalGroups.put(r); @@ -2179,7 +2181,7 @@ async function processReserveBankStatus( if (status.transfer_done) { logger.info("withdrawal: transfer confirmed by bank."); const now = AbsoluteTime.toPreciseTimestamp(AbsoluteTime.now()); - r.wgInfo.bankInfo.timestampBankConfirmed = now; + r.wgInfo.bankInfo.timestampBankConfirmed = timestampPreciseToDb(now); r.status = WithdrawalGroupStatus.PendingQueryingStatus; } else { logger.info("withdrawal: transfer not yet confirmed by bank"); @@ -2285,7 +2287,7 @@ export async function internalPrepareCreateWithdrawalGroup( denomsSel: initialDenomSel, exchangeBaseUrl: canonExchange, instructedAmount: Amounts.stringify(amount), - timestampStart: now, + timestampStart: timestampPreciseToDb(now), rawWithdrawalAmount: initialDenomSel.totalWithdrawCost, effectiveWithdrawalAmount: initialDenomSel.totalCoinValue, secretSeed, @@ -2339,8 +2341,7 @@ export async function internalPerformCreateWithdrawalGroup( if (!prep.creationInfo) { return { withdrawalGroup, transitionInfo: undefined }; } - const { amount, canonExchange, exchangeDetails } = - prep.creationInfo; + const { amount, canonExchange, exchangeDetails } = prep.creationInfo; await tx.withdrawalGroups.add(withdrawalGroup); await tx.reserves.put({ @@ -2350,7 +2351,7 @@ export async function internalPerformCreateWithdrawalGroup( const exchange = await tx.exchanges.get(withdrawalGroup.exchangeBaseUrl); if (exchange) { - exchange.lastWithdrawal = TalerPreciseTimestamp.now(); + exchange.lastWithdrawal = timestampPreciseToDb(TalerPreciseTimestamp.now()); exchange.entryStatus = ExchangeEntryDbRecordStatus.Used; await tx.exchanges.put(exchange); } @@ -2541,11 +2542,7 @@ export async function createManualWithdrawal( }); const exchangePaytoUris = await ws.db - .mktx((x) => [ - x.withdrawalGroups, - x.exchanges, - x.exchangeDetails, - ]) + .mktx((x) => [x.withdrawalGroups, x.exchanges, x.exchangeDetails]) .runReadOnly(async (tx) => { return await getFundingPaytoUris(tx, withdrawalGroup.withdrawalGroupId); }); -- cgit v1.2.3 From 1ce53e1c211296233f2f683c64e156e4d3a79678 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 14 Sep 2023 17:36:15 +0200 Subject: wallet-core: consistently use usec timestamps in DB --- packages/taler-util/src/transactions-types.ts | 24 +++-- .../src/crypto/cryptoImplementation.ts | 22 +++- packages/taler-wallet-core/src/db.ts | 97 ++++++++++++------ .../taler-wallet-core/src/operations/attention.ts | 6 +- .../taler-wallet-core/src/operations/common.ts | 45 ++++---- .../taler-wallet-core/src/operations/deposits.ts | 8 +- .../taler-wallet-core/src/operations/exchanges.ts | 56 +++++++--- .../src/operations/pay-merchant.ts | 22 ++-- .../src/operations/pay-peer-push-debit.ts | 8 +- .../taler-wallet-core/src/operations/pending.ts | 113 ++++++++++++-------- .../taler-wallet-core/src/operations/refresh.ts | 14 +-- .../taler-wallet-core/src/operations/reward.ts | 6 +- .../src/operations/transactions.ts | 17 ++- .../src/operations/withdraw.test.ts | 114 +++++++++++---------- packages/taler-wallet-core/src/pending-types.ts | 14 +-- .../taler-wallet-core/src/util/denominations.ts | 9 +- .../src/util/instructedAmountConversion.ts | 17 +-- 17 files changed, 365 insertions(+), 227 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-util/src/transactions-types.ts b/packages/taler-util/src/transactions-types.ts index 304183ceb..63db206bd 100644 --- a/packages/taler-util/src/transactions-types.ts +++ b/packages/taler-util/src/transactions-types.ts @@ -67,7 +67,7 @@ export interface TransactionsRequest { */ includeRefreshes?: boolean; - filterByState?: TransactionStateFilter + filterByState?: TransactionStateFilter; } export interface TransactionState { @@ -629,6 +629,17 @@ export interface TransactionRefresh extends TransactionCommon { refreshOutputAmount: AmountString; } +export interface DepositTransactionTrackingState { + // Raw wire transfer identifier of the deposit. + wireTransferId: string; + // When was the wire transfer given to the bank. + timestampExecuted: TalerProtocolTimestamp; + // Total amount transfer for this wtid (including fees) + amountRaw: AmountString; + // Wire fee amount for this exchange + wireFee: AmountString; +} + /** * Deposit transaction, which effectively sends * money from this wallet somewhere else. @@ -662,16 +673,7 @@ export interface TransactionDeposit extends TransactionCommon { */ deposited: boolean; - trackingState: Array<{ - // Raw wire transfer identifier of the deposit. - wireTransferId: string; - // When was the wire transfer given to the bank. - timestampExecuted: TalerProtocolTimestamp; - // Total amount transfer for this wtid (including fees) - amountRaw: AmountString; - // Wire fee amount for this exchange - wireFee: AmountString; - }>; + trackingState: Array; } export interface TransactionByIdRequest { diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts index 35777e714..56392f090 100644 --- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts +++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts @@ -87,7 +87,7 @@ import { WithdrawalPlanchet, } from "@gnu-taler/taler-util"; // FIXME: Crypto should not use DB Types! -import { DenominationRecord } from "../db.js"; +import { DenominationRecord, timestampProtocolFromDb } from "../db.js"; import { CreateRecoupRefreshReqRequest, CreateRecoupReqRequest, @@ -962,10 +962,22 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { const value: AmountJson = Amounts.parseOrThrow(denom.value); const p = buildSigPS(TalerSignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY) .put(decodeCrock(masterPub)) - .put(timestampRoundedToBuffer(denom.stampStart)) - .put(timestampRoundedToBuffer(denom.stampExpireWithdraw)) - .put(timestampRoundedToBuffer(denom.stampExpireDeposit)) - .put(timestampRoundedToBuffer(denom.stampExpireLegal)) + .put(timestampRoundedToBuffer(timestampProtocolFromDb(denom.stampStart))) + .put( + timestampRoundedToBuffer( + timestampProtocolFromDb(denom.stampExpireWithdraw), + ), + ) + .put( + timestampRoundedToBuffer( + timestampProtocolFromDb(denom.stampExpireDeposit), + ), + ) + .put( + timestampRoundedToBuffer( + timestampProtocolFromDb(denom.stampExpireLegal), + ), + ) .put(amountToBuffer(value)) .put(amountToBuffer(denom.fees.feeWithdraw)) .put(amountToBuffer(denom.fees.feeDeposit)) diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index cebe3635b..4fc6db68a 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -27,6 +27,7 @@ import { structuredEncapsulate, } from "@gnu-taler/idb-bridge"; import { + AbsoluteTime, AgeCommitmentProof, AmountString, Amounts, @@ -51,12 +52,13 @@ import { TalerPreciseTimestamp, TalerProtocolDuration, TalerProtocolTimestamp, + //TalerProtocolTimestamp, TransactionIdStr, UnblindedSignature, WireInfo, codecForAny, } from "@gnu-taler/taler-util"; -import { RetryInfo, TaskIdentifiers } from "./operations/common.js"; +import { DbRetryInfo, TaskIdentifiers } from "./operations/common.js"; import { DbAccess, DbReadOnlyTransaction, @@ -193,6 +195,44 @@ export function timestampPreciseToDb( } } +export function timestampProtocolToDb( + stamp: TalerProtocolTimestamp, +): DbProtocolTimestamp { + if (stamp.t_s === "never") { + return DB_TIMESTAMP_FOREVER as DbProtocolTimestamp; + } else { + let tUs = stamp.t_s * 1000000; + return tUs as DbProtocolTimestamp; + } +} + +export function timestampProtocolFromDb( + stamp: DbProtocolTimestamp, +): TalerProtocolTimestamp { + return TalerProtocolTimestamp.fromSeconds(Math.floor(stamp / 1000000)); +} + +export function timestampAbsoluteFromDb( + stamp: DbProtocolTimestamp | DbPreciseTimestamp, +): AbsoluteTime { + if (stamp >= DB_TIMESTAMP_FOREVER) { + return AbsoluteTime.never(); + } + return AbsoluteTime.fromMilliseconds(Math.floor(stamp / 1000)); +} + +export function timestampOptionalAbsoluteFromDb( + stamp: DbProtocolTimestamp | DbPreciseTimestamp | undefined, +): AbsoluteTime | undefined { + if (stamp == null) { + return undefined; + } + if (stamp >= DB_TIMESTAMP_FOREVER) { + return AbsoluteTime.never(); + } + return AbsoluteTime.fromMilliseconds(Math.floor(stamp / 1000)); +} + /** * Format of the operation status code: 0x0abc_nnnn @@ -391,22 +431,22 @@ export interface DenominationRecord { /** * Validity start date of the denomination. */ - stampStart: TalerProtocolTimestamp; + stampStart: DbProtocolTimestamp; /** * Date after which the currency can't be withdrawn anymore. */ - stampExpireWithdraw: TalerProtocolTimestamp; + stampExpireWithdraw: DbProtocolTimestamp; /** * Date after the denomination officially doesn't exist anymore. */ - stampExpireLegal: TalerProtocolTimestamp; + stampExpireLegal: DbProtocolTimestamp; /** * Data after which coins of this denomination can't be deposited anymore. */ - stampExpireDeposit: TalerProtocolTimestamp; + stampExpireDeposit: DbProtocolTimestamp; /** * Signature by the exchange's master key over the denomination @@ -448,7 +488,7 @@ export interface DenominationRecord { * Latest list issue date of the "/keys" response * that includes this denomination. */ - listIssueDate: TalerProtocolTimestamp; + listIssueDate: DbProtocolTimestamp; } export namespace DenominationRecord { @@ -460,10 +500,10 @@ export namespace DenominationRecord { feeRefresh: Amounts.stringify(d.fees.feeRefresh), feeRefund: Amounts.stringify(d.fees.feeRefund), feeWithdraw: Amounts.stringify(d.fees.feeWithdraw), - stampExpireDeposit: d.stampExpireDeposit, - stampExpireLegal: d.stampExpireLegal, - stampExpireWithdraw: d.stampExpireWithdraw, - stampStart: d.stampStart, + stampExpireDeposit: timestampProtocolFromDb(d.stampExpireDeposit), + stampExpireLegal: timestampProtocolFromDb(d.stampExpireLegal), + stampExpireWithdraw: timestampProtocolFromDb(d.stampExpireWithdraw), + stampStart: timestampProtocolFromDb(d.stampStart), value: Amounts.stringify(d.value), exchangeBaseUrl: d.exchangeBaseUrl, }; @@ -471,9 +511,9 @@ export namespace DenominationRecord { } export interface ExchangeSignkeysRecord { - stampStart: TalerProtocolTimestamp; - stampExpire: TalerProtocolTimestamp; - stampEnd: TalerProtocolTimestamp; + stampStart: DbProtocolTimestamp; + stampExpire: DbProtocolTimestamp; + stampEnd: DbProtocolTimestamp; signkeyPub: EddsaPublicKeyString; masterSig: EddsaSignatureString; @@ -590,11 +630,6 @@ export enum ExchangeEntryDbUpdateStatus { ReadyUpdate = 7, } -/** - * Timestamp stored as a IEEE 754 double, in milliseconds. - */ -export type DbIndexableTimestampMs = number; - /** * Exchange record as stored in the wallet's database. */ @@ -634,13 +669,8 @@ export interface ExchangeEntryRecord { /** * Next scheduled update for the exchange. - * - * (This field must always be present, so we can index on the timestamp.) - * - * FIXME: To index on the timestamp, this needs to be a number of - * binary timestamp! */ - nextUpdateStampMs: DbIndexableTimestampMs; + nextUpdateStamp: DbPreciseTimestamp; lastKeysEtag: string | undefined; @@ -650,7 +680,7 @@ export interface ExchangeEntryRecord { * Updated whenever the exchange's denominations are updated or when * the refresh check has been done. */ - nextRefreshCheckStampMs: DbIndexableTimestampMs; + nextRefreshCheckStamp: DbPreciseTimestamp; /** * Public key of the reserve that we're currently using for @@ -873,7 +903,7 @@ export interface RewardRecord { /** * Timestamp, the tip can't be picked up anymore after this deadline. */ - rewardExpiration: TalerProtocolTimestamp; + rewardExpiration: DbProtocolTimestamp; /** * The exchange that will sign our coins, chosen by the merchant. @@ -1287,7 +1317,7 @@ export interface PurchaseRecord { /** * Continue querying the refund status until this deadline has expired. */ - autoRefundDeadline: TalerProtocolTimestamp | undefined; + autoRefundDeadline: DbProtocolTimestamp | undefined; /** * How much merchant has refund to be taken but the wallet @@ -1668,7 +1698,7 @@ export interface DepositTrackingInfo { // Raw wire transfer identifier of the deposit. wireTransferId: string; // When was the wire transfer given to the bank. - timestampExecuted: TalerProtocolTimestamp; + timestampExecuted: DbProtocolTimestamp; // Total amount transfer for this wtid (including fees) amountRaw: AmountString; // Wire fee amount for this exchange @@ -1690,7 +1720,7 @@ export interface DepositGroupRecord { */ amount: AmountString; - wireTransferDeadline: TalerProtocolTimestamp; + wireTransferDeadline: DbProtocolTimestamp; merchantPub: string; merchantPriv: string; @@ -1831,7 +1861,7 @@ export interface PeerPushDebitRecord { */ contractEncNonce: string; - purseExpiration: TalerProtocolTimestamp; + purseExpiration: DbProtocolTimestamp; timestampCreated: DbPreciseTimestamp; @@ -2077,7 +2107,7 @@ export interface OperationRetryRecord { lastError?: TalerErrorDetail; - retryInfo: RetryInfo; + retryInfo: DbRetryInfo; } /** @@ -2130,9 +2160,8 @@ export interface UserAttentionRecord { /** * When the notification was created. - * FIXME: This should be a TalerPreciseTimestamp */ - createdMs: number; + created: DbPreciseTimestamp; /** * When the user mark this notification as read. @@ -2233,7 +2262,7 @@ export interface RefundItemRecord { /** * Execution time as claimed by the merchant */ - executionTime: TalerProtocolTimestamp; + executionTime: DbProtocolTimestamp; /** * Time when the wallet became aware of the refund. diff --git a/packages/taler-wallet-core/src/operations/attention.ts b/packages/taler-wallet-core/src/operations/attention.ts index 1030db0a6..92d69e93e 100644 --- a/packages/taler-wallet-core/src/operations/attention.ts +++ b/packages/taler-wallet-core/src/operations/attention.ts @@ -31,7 +31,7 @@ import { UserAttentionUnreadList, } from "@gnu-taler/taler-util"; import { InternalWalletState } from "../internal-wallet-state.js"; -import { timestampPreciseToDb } from "../index.js"; +import { timestampPreciseFromDb, timestampPreciseToDb } from "../index.js"; const logger = new Logger("operations/attention.ts"); @@ -75,7 +75,7 @@ export async function getUserAttentions( return; pending.push({ info: x.info, - when: TalerPreciseTimestamp.fromMilliseconds(x.createdMs), + when: timestampPreciseFromDb(x.created), read: x.read !== undefined, }); }); @@ -118,7 +118,7 @@ export async function addAttentionRequest( await tx.userAttention.put({ info, entityId, - createdMs: AbsoluteTime.now().t_ms as number, + created: timestampPreciseToDb(TalerPreciseTimestamp.now()), read: undefined, }); }); diff --git a/packages/taler-wallet-core/src/operations/common.ts b/packages/taler-wallet-core/src/operations/common.ts index 50dd3dc5c..e8e492c08 100644 --- a/packages/taler-wallet-core/src/operations/common.ts +++ b/packages/taler-wallet-core/src/operations/common.ts @@ -40,6 +40,7 @@ import { TalerError, TalerErrorCode, TalerErrorDetail, + TalerPreciseTimestamp, TombstoneIdStr, TransactionIdStr, TransactionType, @@ -49,6 +50,7 @@ import { CryptoApiStoppedError } from "../crypto/workers/crypto-dispatcher.js"; import { BackupProviderRecord, CoinRecord, + DbPreciseTimestamp, DepositGroupRecord, ExchangeDetailsRecord, ExchangeEntryDbRecordStatus, @@ -62,6 +64,7 @@ import { RecoupGroupRecord, RefreshGroupRecord, RewardRecord, + timestampPreciseToDb, WalletStoresV1, WithdrawalGroupRecord, } from "../db.js"; @@ -360,11 +363,11 @@ async function storePendingTaskError( retryRecord = { id: pendingTaskId, lastError: e, - retryInfo: RetryInfo.reset(), + retryInfo: DbRetryInfo.reset(), }; } else { retryRecord.lastError = e; - retryRecord.retryInfo = RetryInfo.increment(retryRecord.retryInfo); + retryRecord.retryInfo = DbRetryInfo.increment(retryRecord.retryInfo); } await tx.operationRetries.put(retryRecord); return taskToTransactionNotification(ws, tx, pendingTaskId, e); @@ -383,7 +386,7 @@ export async function resetPendingTaskTimeout( if (retryRecord) { // Note that we don't reset the lastError, it should still be visible // while the retry runs. - retryRecord.retryInfo = RetryInfo.reset(); + retryRecord.retryInfo = DbRetryInfo.reset(); await tx.operationRetries.put(retryRecord); } return taskToTransactionNotification(ws, tx, pendingTaskId, undefined); @@ -403,14 +406,14 @@ async function storePendingTaskPending( if (!retryRecord) { retryRecord = { id: pendingTaskId, - retryInfo: RetryInfo.reset(), + retryInfo: DbRetryInfo.reset(), }; } else { if (retryRecord.lastError) { hadError = true; } delete retryRecord.lastError; - retryRecord.retryInfo = RetryInfo.increment(retryRecord.retryInfo); + retryRecord.retryInfo = DbRetryInfo.increment(retryRecord.retryInfo); } await tx.operationRetries.put(retryRecord); if (hadError) { @@ -736,9 +739,9 @@ export interface TaskRunLongpollResult { type: TaskRunResultType.Longpoll; } -export interface RetryInfo { - firstTry: AbsoluteTime; - nextRetry: AbsoluteTime; +export interface DbRetryInfo { + firstTry: DbPreciseTimestamp; + nextRetry: DbPreciseTimestamp; retryCounter: number; } @@ -755,7 +758,7 @@ const defaultRetryPolicy: RetryPolicy = { }; function updateTimeout( - r: RetryInfo, + r: DbRetryInfo, p: RetryPolicy = defaultRetryPolicy, ): void { const now = AbsoluteTime.now(); @@ -763,7 +766,9 @@ function updateTimeout( throw Error("assertion failed"); } if (p.backoffDelta.d_ms === "forever") { - r.nextRetry = AbsoluteTime.never(); + r.nextRetry = timestampPreciseToDb( + AbsoluteTime.toPreciseTimestamp(AbsoluteTime.never()), + ); return; } @@ -775,12 +780,12 @@ function updateTimeout( (p.maxTimeout.d_ms === "forever" ? nextIncrement : Math.min(p.maxTimeout.d_ms, nextIncrement)); - r.nextRetry = AbsoluteTime.fromMilliseconds(t); + r.nextRetry = timestampPreciseToDb(TalerPreciseTimestamp.fromMilliseconds(t)); } -export namespace RetryInfo { +export namespace DbRetryInfo { export function getDuration( - r: RetryInfo | undefined, + r: DbRetryInfo | undefined, p: RetryPolicy = defaultRetryPolicy, ): Duration { if (!r) { @@ -797,11 +802,11 @@ export namespace RetryInfo { }; } - export function reset(p: RetryPolicy = defaultRetryPolicy): RetryInfo { - const now = AbsoluteTime.now(); - const info = { - firstTry: now, - nextRetry: now, + export function reset(p: RetryPolicy = defaultRetryPolicy): DbRetryInfo { + const now = TalerPreciseTimestamp.now(); + const info: DbRetryInfo = { + firstTry: timestampPreciseToDb(now), + nextRetry: timestampPreciseToDb(now), retryCounter: 0, }; updateTimeout(info, p); @@ -809,9 +814,9 @@ export namespace RetryInfo { } export function increment( - r: RetryInfo | undefined, + r: DbRetryInfo | undefined, p: RetryPolicy = defaultRetryPolicy, - ): RetryInfo { + ): DbRetryInfo { if (!r) { return reset(p); } diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts index cb40f8f22..111d15989 100644 --- a/packages/taler-wallet-core/src/operations/deposits.ts +++ b/packages/taler-wallet-core/src/operations/deposits.ts @@ -74,6 +74,8 @@ import { createRefreshGroup, getTotalRefreshCost, timestampPreciseToDb, + timestampProtocolFromDb, + timestampProtocolToDb, } from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; import { assertUnreachable } from "../util/assertUnreachable.js"; @@ -800,7 +802,7 @@ async function processDepositGroupPendingTrack( amountRaw: Amounts.stringify(raw), wireFee: Amounts.stringify(wireFee), exchangePub: track.exchange_pub, - timestampExecuted: track.execution_time, + timestampExecuted: timestampProtocolToDb(track.execution_time), wireTransferId: track.wtid, }, id: track.exchange_sig, @@ -1393,7 +1395,9 @@ export async function createDepositGroup( counterpartyEffectiveDepositAmount: Amounts.stringify( counterpartyEffectiveDepositAmount, ), - wireTransferDeadline: contractTerms.wire_transfer_deadline, + wireTransferDeadline: timestampProtocolToDb( + contractTerms.wire_transfer_deadline, + ), wire: { payto_uri: req.depositPaytoUri, salt: wireSalt, diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts index 60d55252a..5e966b719 100644 --- a/packages/taler-wallet-core/src/operations/exchanges.ts +++ b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -74,7 +74,9 @@ import { ExchangeEntryDbRecordStatus, ExchangeEntryDbUpdateStatus, isWithdrawableDenom, + timestampPreciseFromDb, timestampPreciseToDb, + timestampProtocolToDb, WalletDbReadWriteTransaction, } from "../index.js"; import { InternalWalletState, TrustInfo } from "../internal-wallet-state.js"; @@ -317,8 +319,12 @@ export async function addPresetExchangeEntry( detailsPointer: undefined, lastUpdate: undefined, lastKeysEtag: undefined, - nextRefreshCheckStampMs: AbsoluteTime.getStampMsNever(), - nextUpdateStampMs: AbsoluteTime.getStampMsNever(), + nextRefreshCheckStamp: timestampPreciseToDb( + AbsoluteTime.toPreciseTimestamp(AbsoluteTime.never()), + ), + nextUpdateStamp: timestampPreciseToDb( + AbsoluteTime.toPreciseTimestamp(AbsoluteTime.never()), + ), }; await tx.exchanges.put(r); } @@ -344,8 +350,12 @@ export async function provideExchangeRecordInTx( baseUrl: baseUrl, detailsPointer: undefined, lastUpdate: undefined, - nextUpdateStampMs: AbsoluteTime.getStampMsNever(), - nextRefreshCheckStampMs: AbsoluteTime.getStampMsNever(), + nextUpdateStamp: timestampPreciseToDb( + AbsoluteTime.toPreciseTimestamp(AbsoluteTime.never()), + ), + nextRefreshCheckStamp: timestampPreciseToDb( + AbsoluteTime.toPreciseTimestamp(AbsoluteTime.never()), + ), lastKeysEtag: undefined, }; await tx.exchanges.put(r); @@ -446,13 +456,19 @@ async function downloadExchangeKeysInfo( isRevoked: false, value: Amounts.stringify(value), currency: value.currency, - stampExpireDeposit: denomIn.stamp_expire_deposit, - stampExpireLegal: denomIn.stamp_expire_legal, - stampExpireWithdraw: denomIn.stamp_expire_withdraw, - stampStart: denomIn.stamp_start, + stampExpireDeposit: timestampProtocolToDb( + denomIn.stamp_expire_deposit, + ), + stampExpireLegal: timestampProtocolToDb(denomIn.stamp_expire_legal), + stampExpireWithdraw: timestampProtocolToDb( + denomIn.stamp_expire_withdraw, + ), + stampStart: timestampProtocolToDb(denomIn.stamp_start), verificationStatus: DenominationVerificationStatus.Unverified, masterSig: denomIn.master_sig, - listIssueDate: exchangeKeysJsonUnchecked.list_issue_date, + listIssueDate: timestampProtocolToDb( + exchangeKeysJsonUnchecked.list_issue_date, + ), fees: { feeDeposit: Amounts.stringify(denomGroup.fee_deposit), feeRefresh: Amounts.stringify(denomGroup.fee_refresh), @@ -614,7 +630,9 @@ export async function updateExchangeFromUrlHandler( !forceNow && exchangeDetails !== undefined && !AbsoluteTime.isExpired( - AbsoluteTime.fromStampMs(exchange.nextUpdateStampMs), + AbsoluteTime.fromPreciseTimestamp( + timestampPreciseFromDb(exchange.nextUpdateStamp), + ), ) ) { logger.trace("using existing exchange info"); @@ -755,11 +773,15 @@ export async function updateExchangeFromUrlHandler( newDetails.rowId = existingDetails.rowId; } r.lastUpdate = timestampPreciseToDb(TalerPreciseTimestamp.now()); - r.nextUpdateStampMs = AbsoluteTime.toStampMs( - AbsoluteTime.fromProtocolTimestamp(keysInfo.expiry), + r.nextUpdateStamp = timestampPreciseToDb( + AbsoluteTime.toPreciseTimestamp( + AbsoluteTime.fromProtocolTimestamp(keysInfo.expiry), + ), ); // New denominations might be available. - r.nextRefreshCheckStampMs = AbsoluteTime.getStampMsNow(); + r.nextRefreshCheckStamp = timestampPreciseToDb( + TalerPreciseTimestamp.now(), + ); if (detailsPointerChanged) { r.detailsPointer = { currency: newDetails.currency, @@ -777,9 +799,9 @@ export async function updateExchangeFromUrlHandler( exchangeDetailsRowId: drRowId.key, masterSig: sk.master_sig, signkeyPub: sk.key, - stampEnd: sk.stamp_end, - stampExpire: sk.stamp_expire, - stampStart: sk.stamp_start, + stampEnd: timestampProtocolToDb(sk.stamp_end), + stampExpire: timestampProtocolToDb(sk.stamp_expire), + stampStart: timestampProtocolToDb(sk.stamp_start), }); } @@ -814,7 +836,7 @@ export async function updateExchangeFromUrlHandler( ); } } else { - x.listIssueDate = keysInfo.listIssueDate; + x.listIssueDate = timestampProtocolToDb(keysInfo.listIssueDate); if (!x.isOffered) { x.isOffered = true; logger.info( diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts index 97bf6e2a6..157541ed3 100644 --- a/packages/taler-wallet-core/src/operations/pay-merchant.ts +++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts @@ -104,6 +104,8 @@ import { RefundItemRecord, RefundItemStatus, timestampPreciseToDb, + timestampProtocolFromDb, + timestampProtocolToDb, } from "../index.js"; import { EXCHANGE_COINS_LOCK, @@ -115,7 +117,7 @@ import { checkDbInvariant } from "../util/invariants.js"; import { GetReadOnlyAccess } from "../util/query.js"; import { constructTaskIdentifier, - RetryInfo, + DbRetryInfo, runLongpollAsync, runTaskWithErrorReporting, spendCoins, @@ -217,11 +219,13 @@ async function failProposalPermanently( notifyTransition(ws, transactionId, transitionInfo); } -function getProposalRequestTimeout(retryInfo?: RetryInfo): Duration { +function getProposalRequestTimeout(retryInfo?: DbRetryInfo): Duration { return Duration.clamp({ lower: Duration.fromSpec({ seconds: 1 }), upper: Duration.fromSpec({ seconds: 60 }), - value: retryInfo ? RetryInfo.getDuration(retryInfo) : Duration.fromSpec({}), + value: retryInfo + ? DbRetryInfo.getDuration(retryInfo) + : Duration.fromSpec({}), }); } @@ -738,8 +742,10 @@ async function storeFirstPaySuccess( const ar = Duration.fromTalerProtocolDuration(protoAr); logger.info("auto_refund present"); purchase.purchaseStatus = PurchaseStatus.PendingQueryingAutoRefund; - purchase.autoRefundDeadline = AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.addDuration(AbsoluteTime.now(), ar), + purchase.autoRefundDeadline = timestampProtocolToDb( + AbsoluteTime.toProtocolTimestamp( + AbsoluteTime.addDuration(AbsoluteTime.now(), ar), + ), ); } await tx.purchases.put(purchase); @@ -2343,7 +2349,9 @@ async function processPurchaseAutoRefund( if ( !purchase.autoRefundDeadline || AbsoluteTime.isExpired( - AbsoluteTime.fromProtocolTimestamp(purchase.autoRefundDeadline), + AbsoluteTime.fromProtocolTimestamp( + timestampProtocolFromDb(purchase.autoRefundDeadline), + ), ) ) { const transitionInfo = await ws.db @@ -2804,7 +2812,7 @@ async function storeRefunds( const status: RefundItemStatus = getItemStatus(rf); const newItem: RefundItemRecord = { coinPub: rf.coin_pub, - executionTime: rf.execution_time, + executionTime: timestampProtocolToDb(rf.execution_time), obtainedTime: timestampPreciseToDb(now), refundAmount: rf.refund_amount, refundGroupId: newGroup.refundGroupId, diff --git a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts index b3d0eb132..a7b9f79eb 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts @@ -56,10 +56,13 @@ import { RefreshOperationStatus, createRefreshGroup, timestampPreciseToDb, + timestampProtocolFromDb, + timestampProtocolToDb, } from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; import { PendingTaskType } from "../pending-types.js"; import { assertUnreachable } from "../util/assertUnreachable.js"; +import { PeerCoinRepair, selectPeerCoins } from "../util/coinSelection.js"; import { checkLogicInvariant } from "../util/invariants.js"; import { TaskRunResult, @@ -78,7 +81,6 @@ import { notifyTransition, stopLongpolling, } from "./transactions.js"; -import { PeerCoinRepair, selectPeerCoins } from "../util/coinSelection.js"; const logger = new Logger("pay-peer-push-debit.ts"); @@ -208,7 +210,7 @@ async function processPeerPushDebitCreateReserve( mergePub: peerPushInitiation.mergePub, minAge: 0, purseAmount: peerPushInitiation.amount, - purseExpiration, + purseExpiration: timestampProtocolFromDb(purseExpiration), pursePriv: peerPushInitiation.pursePriv, }); @@ -667,7 +669,7 @@ export async function initiatePeerPushDebit( exchangeBaseUrl: sel.exchangeBaseUrl, mergePriv: mergePair.priv, mergePub: mergePair.pub, - purseExpiration: purseExpiration, + purseExpiration: timestampProtocolToDb(purseExpiration), pursePriv: pursePair.priv, pursePub: pursePair.pub, timestampCreated: timestampPreciseToDb(TalerPreciseTimestamp.now()), diff --git a/packages/taler-wallet-core/src/operations/pending.ts b/packages/taler-wallet-core/src/operations/pending.ts index 120d316ce..1819aa1b8 100644 --- a/packages/taler-wallet-core/src/operations/pending.ts +++ b/packages/taler-wallet-core/src/operations/pending.ts @@ -21,43 +21,46 @@ /** * Imports. */ +import { GlobalIDB } from "@gnu-taler/idb-bridge"; +import { AbsoluteTime, TransactionRecordFilter } from "@gnu-taler/taler-util"; import { - PurchaseStatus, - WalletStoresV1, BackupProviderStateTag, - RefreshCoinStatus, - PeerPushDebitStatus, - PeerPullDebitRecordStatus, - PeerPushCreditStatus, - PeerPullPaymentCreditStatus, - WithdrawalGroupStatus, - RewardRecordStatus, - DepositOperationStatus, - RefreshGroupRecord, - WithdrawalGroupRecord, + DepositElementStatus, DepositGroupRecord, - RewardRecord, - PurchaseRecord, + DepositOperationStatus, + ExchangeEntryDbUpdateStatus, PeerPullCreditRecord, + PeerPullDebitRecordStatus, + PeerPullPaymentCreditStatus, PeerPullPaymentIncomingRecord, + PeerPushCreditStatus, PeerPushDebitRecord, + PeerPushDebitStatus, PeerPushPaymentIncomingRecord, + PurchaseRecord, + PurchaseStatus, + RefreshCoinStatus, + RefreshGroupRecord, + RefreshOperationStatus, RefundGroupRecord, RefundGroupStatus, - ExchangeEntryDbUpdateStatus, - RefreshOperationStatus, - DepositElementStatus, + RewardRecord, + RewardRecordStatus, + WalletStoresV1, + WithdrawalGroupRecord, + WithdrawalGroupStatus, + timestampAbsoluteFromDb, + timestampOptionalAbsoluteFromDb, timestampPreciseFromDb, + timestampPreciseToDb, } from "../db.js"; +import { InternalWalletState } from "../internal-wallet-state.js"; import { PendingOperationsResponse, PendingTaskType, TaskId, } from "../pending-types.js"; -import { AbsoluteTime, TransactionRecordFilter } from "@gnu-taler/taler-util"; -import { InternalWalletState } from "../internal-wallet-state.js"; import { GetReadOnlyAccess } from "../util/query.js"; -import { GlobalIDB } from "@gnu-taler/idb-bridge"; import { TaskIdentifiers } from "./common.js"; function getPendingCommon( @@ -100,12 +103,14 @@ async function gatherExchangePending( } const opTag = TaskIdentifiers.forExchangeUpdate(exch); let opr = await tx.operationRetries.get(opTag); - const timestampDue = - opr?.retryInfo.nextRetry ?? - AbsoluteTime.fromStampMs(exch.nextUpdateStampMs); + const timestampDue = opr?.retryInfo.nextRetry ?? exch.nextRefreshCheckStamp; resp.pendingOperations.push({ type: PendingTaskType.ExchangeUpdate, - ...getPendingCommon(ws, opTag, timestampDue), + ...getPendingCommon( + ws, + opTag, + AbsoluteTime.fromPreciseTimestamp(timestampPreciseFromDb(timestampDue)), + ), givesLifeness: false, exchangeBaseUrl: exch.baseUrl, lastError: opr?.lastError, @@ -116,8 +121,16 @@ async function gatherExchangePending( if (!opr?.lastError) { resp.pendingOperations.push({ type: PendingTaskType.ExchangeCheckRefresh, - ...getPendingCommon(ws, opTag, timestampDue), - timestampDue: AbsoluteTime.fromStampMs(exch.nextRefreshCheckStampMs), + ...getPendingCommon( + ws, + opTag, + AbsoluteTime.fromPreciseTimestamp( + timestampPreciseFromDb(timestampDue), + ), + ), + timestampDue: AbsoluteTime.fromPreciseTimestamp( + timestampPreciseFromDb(exch.nextRefreshCheckStamp), + ), givesLifeness: false, exchangeBaseUrl: exch.baseUrl, }); @@ -166,7 +179,9 @@ async function gatherRefreshPending( } const opId = TaskIdentifiers.forRefresh(r); const retryRecord = await tx.operationRetries.get(opId); - const timestampDue = retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); + const timestampDue = + timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ?? + AbsoluteTime.now(); resp.pendingOperations.push({ type: PendingTaskType.Refresh, ...getPendingCommon(ws, opId, timestampDue), @@ -223,8 +238,8 @@ async function gatherWithdrawalPending( opr = { id: opTag, retryInfo: { - firstTry: now, - nextRetry: now, + firstTry: timestampPreciseToDb(AbsoluteTime.toPreciseTimestamp(now)), + nextRetry: timestampPreciseToDb(AbsoluteTime.toPreciseTimestamp(now)), retryCounter: 0, }, }; @@ -234,7 +249,8 @@ async function gatherWithdrawalPending( ...getPendingCommon( ws, opTag, - opr.retryInfo?.nextRetry ?? AbsoluteTime.now(), + timestampOptionalAbsoluteFromDb(opr.retryInfo?.nextRetry) ?? + AbsoluteTime.now(), ), givesLifeness: true, withdrawalGroupId: wsr.withdrawalGroupId, @@ -286,7 +302,9 @@ async function gatherDepositPending( } const opId = TaskIdentifiers.forDeposit(dg); const retryRecord = await tx.operationRetries.get(opId); - const timestampDue = retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); + const timestampDue = + timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ?? + AbsoluteTime.now(); resp.pendingOperations.push({ type: PendingTaskType.Deposit, ...getPendingCommon(ws, opId, timestampDue), @@ -331,13 +349,15 @@ async function gatherRewardPending( await iterRecordsForReward(tx, { onlyState: "nonfinal" }, async (tip) => { const opId = TaskIdentifiers.forTipPickup(tip); const retryRecord = await tx.operationRetries.get(opId); - const timestampDue = retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); + const timestampDue = + timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ?? + AbsoluteTime.now(); if (tip.acceptedTimestamp) { resp.pendingOperations.push({ type: PendingTaskType.RewardPickup, ...getPendingCommon(ws, opId, timestampDue), givesLifeness: true, - timestampDue: retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(), + timestampDue, merchantBaseUrl: tip.merchantBaseUrl, tipId: tip.walletRewardId, merchantTipId: tip.merchantRewardId, @@ -391,7 +411,9 @@ async function gatherPurchasePending( await iterRecordsForPurchase(tx, { onlyState: "nonfinal" }, async (pr) => { const opId = TaskIdentifiers.forPay(pr); const retryRecord = await tx.operationRetries.get(opId); - const timestampDue = retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); + const timestampDue = + timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ?? + AbsoluteTime.now(); resp.pendingOperations.push({ type: PendingTaskType.Purchase, ...getPendingCommon(ws, opId, timestampDue), @@ -420,7 +442,9 @@ async function gatherRecoupPending( } const opId = TaskIdentifiers.forRecoup(rg); const retryRecord = await tx.operationRetries.get(opId); - const timestampDue = retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); + const timestampDue = + timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ?? + AbsoluteTime.now(); resp.pendingOperations.push({ type: PendingTaskType.Recoup, ...getPendingCommon(ws, opId, timestampDue), @@ -445,8 +469,8 @@ async function gatherBackupPending( const opId = TaskIdentifiers.forBackup(bp); const retryRecord = await tx.operationRetries.get(opId); if (bp.state.tag === BackupProviderStateTag.Ready) { - const timestampDue = AbsoluteTime.fromPreciseTimestamp( - timestampPreciseFromDb(bp.state.nextBackupTimestamp), + const timestampDue = timestampAbsoluteFromDb( + bp.state.nextBackupTimestamp, ); resp.pendingOperations.push({ type: PendingTaskType.Backup, @@ -457,7 +481,8 @@ async function gatherBackupPending( }); } else if (bp.state.tag === BackupProviderStateTag.Retrying) { const timestampDue = - retryRecord?.retryInfo?.nextRetry ?? AbsoluteTime.now(); + timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo?.nextRetry) ?? + AbsoluteTime.now(); resp.pendingOperations.push({ type: PendingTaskType.Backup, ...getPendingCommon(ws, opId, timestampDue), @@ -504,7 +529,8 @@ async function gatherPeerPullInitiationPending( const opId = TaskIdentifiers.forPeerPullPaymentInitiation(pi); const retryRecord = await tx.operationRetries.get(opId); const timestampDue = - retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); + timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ?? + AbsoluteTime.now(); resp.pendingOperations.push({ type: PendingTaskType.PeerPullCredit, ...getPendingCommon(ws, opId, timestampDue), @@ -550,7 +576,8 @@ async function gatherPeerPullDebitPending( const opId = TaskIdentifiers.forPeerPullPaymentDebit(pi); const retryRecord = await tx.operationRetries.get(opId); const timestampDue = - retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); + timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ?? + AbsoluteTime.now(); resp.pendingOperations.push({ type: PendingTaskType.PeerPullDebit, ...getPendingCommon(ws, opId, timestampDue), @@ -596,7 +623,8 @@ async function gatherPeerPushInitiationPending( const opId = TaskIdentifiers.forPeerPushPaymentInitiation(pi); const retryRecord = await tx.operationRetries.get(opId); const timestampDue = - retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); + timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ?? + AbsoluteTime.now(); resp.pendingOperations.push({ type: PendingTaskType.PeerPushDebit, ...getPendingCommon(ws, opId, timestampDue), @@ -646,7 +674,8 @@ async function gatherPeerPushCreditPending( const opId = TaskIdentifiers.forPeerPushCredit(pi); const retryRecord = await tx.operationRetries.get(opId); const timestampDue = - retryRecord?.retryInfo.nextRetry ?? AbsoluteTime.now(); + timestampOptionalAbsoluteFromDb(retryRecord?.retryInfo.nextRetry) ?? + AbsoluteTime.now(); resp.pendingOperations.push({ type: PendingTaskType.PeerPushCredit, ...getPendingCommon(ws, opId, timestampDue), diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts index dc1d53627..95aedbbd6 100644 --- a/packages/taler-wallet-core/src/operations/refresh.ts +++ b/packages/taler-wallet-core/src/operations/refresh.ts @@ -81,6 +81,7 @@ import { PendingTaskType, RefreshSessionRecord, timestampPreciseToDb, + timestampProtocolFromDb, } from "../index.js"; import { EXCHANGE_COINS_LOCK, @@ -1125,10 +1126,10 @@ export async function createRefreshGroup( */ function getAutoRefreshCheckThreshold(d: DenominationRecord): AbsoluteTime { const expireWithdraw = AbsoluteTime.fromProtocolTimestamp( - d.stampExpireWithdraw, + timestampProtocolFromDb(d.stampExpireWithdraw), ); const expireDeposit = AbsoluteTime.fromProtocolTimestamp( - d.stampExpireDeposit, + timestampProtocolFromDb(d.stampExpireDeposit), ); const delta = AbsoluteTime.difference(expireWithdraw, expireDeposit); const deltaDiv = durationMul(delta, 0.75); @@ -1140,10 +1141,10 @@ function getAutoRefreshCheckThreshold(d: DenominationRecord): AbsoluteTime { */ function getAutoRefreshExecuteThreshold(d: DenominationRecord): AbsoluteTime { const expireWithdraw = AbsoluteTime.fromProtocolTimestamp( - d.stampExpireWithdraw, + timestampProtocolFromDb(d.stampExpireWithdraw), ); const expireDeposit = AbsoluteTime.fromProtocolTimestamp( - d.stampExpireDeposit, + timestampProtocolFromDb(d.stampExpireDeposit), ); const delta = AbsoluteTime.difference(expireWithdraw, expireDeposit); const deltaDiv = durationMul(delta, 0.5); @@ -1227,8 +1228,9 @@ export async function autoRefresh( logger.trace( `next refresh check at ${AbsoluteTime.toIsoString(minCheckThreshold)}`, ); - exchange.nextRefreshCheckStampMs = - AbsoluteTime.toStampMs(minCheckThreshold); + exchange.nextRefreshCheckStamp = timestampPreciseToDb( + AbsoluteTime.toPreciseTimestamp(minCheckThreshold), + ); await tx.exchanges.put(exchange); }); return TaskRunResult.finished(); diff --git a/packages/taler-wallet-core/src/operations/reward.ts b/packages/taler-wallet-core/src/operations/reward.ts index 3681dc4f5..ddcfb20ac 100644 --- a/packages/taler-wallet-core/src/operations/reward.ts +++ b/packages/taler-wallet-core/src/operations/reward.ts @@ -52,6 +52,8 @@ import { RewardRecordStatus, timestampPreciseFromDb, timestampPreciseToDb, + timestampProtocolFromDb, + timestampProtocolToDb, } from "../db.js"; import { makeErrorDetail } from "@gnu-taler/taler-util"; import { InternalWalletState } from "../internal-wallet-state.js"; @@ -201,7 +203,7 @@ export async function prepareTip( acceptedTimestamp: undefined, status: RewardRecordStatus.DialogAccept, rewardAmountRaw: Amounts.stringify(amount), - rewardExpiration: tipPickupStatus.expiration, + rewardExpiration: timestampProtocolToDb(tipPickupStatus.expiration), exchangeBaseUrl: tipPickupStatus.exchange_url, next_url: tipPickupStatus.next_url, merchantBaseUrl: res.merchantBaseUrl, @@ -231,7 +233,7 @@ export async function prepareTip( rewardAmountRaw: Amounts.stringify(tipRecord.rewardAmountRaw), exchangeBaseUrl: tipRecord.exchangeBaseUrl, merchantBaseUrl: tipRecord.merchantBaseUrl, - expirationTimestamp: tipRecord.rewardExpiration, + expirationTimestamp: timestampProtocolFromDb(tipRecord.rewardExpiration), rewardAmountEffective: Amounts.stringify(tipRecord.rewardAmountEffective), walletRewardId: tipRecord.walletRewardId, transactionId, diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts index 41bdae249..cf2006406 100644 --- a/packages/taler-wallet-core/src/operations/transactions.ts +++ b/packages/taler-wallet-core/src/operations/transactions.ts @@ -20,6 +20,7 @@ import { AbsoluteTime, Amounts, + DepositTransactionTrackingState, j2s, Logger, NotificationType, @@ -69,6 +70,7 @@ import { GetReadOnlyAccess, timestampOptionalPreciseFromDb, timestampPreciseFromDb, + timestampProtocolFromDb, WalletStoresV1, } from "../index.js"; import { InternalWalletState } from "../internal-wallet-state.js"; @@ -809,6 +811,17 @@ function buildTransactionForDeposit( } } + const trackingState: DepositTransactionTrackingState[] = []; + + for (const ts of Object.values(dg.trackingState ?? {})) { + trackingState.push({ + amountRaw: ts.amountRaw, + timestampExecuted: timestampProtocolFromDb(ts.timestampExecuted), + wireFee: ts.wireFee, + wireTransferId: ts.wireTransferId, + }); + } + return { type: TransactionType.Deposit, txState: computeDepositTransactionStatus(dg), @@ -817,7 +830,7 @@ function buildTransactionForDeposit( amountEffective: Amounts.stringify(dg.totalPayCost), timestamp: timestampPreciseFromDb(dg.timestampCreated), targetPaytoUri: dg.wire.payto_uri, - wireTransferDeadline: dg.wireTransferDeadline, + wireTransferDeadline: timestampProtocolFromDb(dg.wireTransferDeadline), transactionId: constructTransactionIdentifier({ tag: TransactionType.Deposit, depositGroupId: dg.depositGroupId, @@ -830,7 +843,7 @@ function buildTransactionForDeposit( )) / dg.statusPerCoin.length, depositGroupId: dg.depositGroupId, - trackingState: Object.values(dg.trackingState ?? {}), + trackingState, deposited, ...(ort?.lastError ? { error: ort.lastError } : {}), }; diff --git a/packages/taler-wallet-core/src/operations/withdraw.test.ts b/packages/taler-wallet-core/src/operations/withdraw.test.ts index 2d9286610..cb8aa5e81 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.test.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.test.ts @@ -16,7 +16,11 @@ import { Amounts, DenomKeyType } from "@gnu-taler/taler-util"; import test from "ava"; -import { DenominationRecord, DenominationVerificationStatus } from "../db.js"; +import { + DenominationRecord, + DenominationVerificationStatus, + timestampProtocolToDb, +} from "../db.js"; import { selectWithdrawalDenominations } from "../util/coinSelection.js"; test("withdrawal selection bug repro", (t) => { @@ -64,22 +68,22 @@ test("withdrawal selection bug repro", (t) => { isRevoked: false, masterSig: "4F0P456CNNTTWK8BFJHGM3JTD6FVVNZY8EP077GYAHDJ5Y81S5RQ3SMS925NXMDVG9A88JAAP0E2GDZBC21PP5NHFFVWHAW3AVT8J3R", - stampExpireDeposit: { + stampExpireDeposit: timestampProtocolToDb({ t_s: 1742909388, - }, - stampExpireLegal: { + }), + stampExpireLegal: timestampProtocolToDb({ t_s: 1900589388, - }, - stampExpireWithdraw: { + }), + stampExpireWithdraw: timestampProtocolToDb({ t_s: 1679837388, - }, - stampStart: { + }), + stampStart: timestampProtocolToDb({ t_s: 1585229388, - }, + }), verificationStatus: DenominationVerificationStatus.Unverified, currency: "KUDOS", value: "KUDOS:1000", - listIssueDate: { t_s: 0 }, + listIssueDate: timestampProtocolToDb({ t_s: 0 }), }, { denomPub: { @@ -119,22 +123,22 @@ test("withdrawal selection bug repro", (t) => { isRevoked: false, masterSig: "P99AW82W46MZ0AKW7Z58VQPXFNTJQM9DVTYPBDF6KVYF38PPVDAZTV7JQ8TY7HGEC7JJJAY4E7AY7J3W1WV10DAZZQHHKTAVTSRAC20", - stampExpireDeposit: { + stampExpireDeposit: timestampProtocolToDb({ t_s: 1742909388, - }, - stampExpireLegal: { + }), + stampExpireLegal: timestampProtocolToDb({ t_s: 1900589388, - }, - stampExpireWithdraw: { + }), + stampExpireWithdraw: timestampProtocolToDb({ t_s: 1679837388, - }, - stampStart: { + }), + stampStart: timestampProtocolToDb({ t_s: 1585229388, - }, + }), verificationStatus: DenominationVerificationStatus.Unverified, value: "KUDOS:10", currency: "KUDOS", - listIssueDate: { t_s: 0 }, + listIssueDate: timestampProtocolToDb({ t_s: 0 }), }, { denomPub: { @@ -173,22 +177,22 @@ test("withdrawal selection bug repro", (t) => { isRevoked: false, masterSig: "8S4VZGHE5WE0N5ZVCHYW9KZZR4YAKK15S46MV1HR1QB9AAMH3NWPW4DCR4NYGJK33Q8YNFY80SWNS6XKAP5DEVK933TM894FJ2VGE3G", - stampExpireDeposit: { + stampExpireDeposit: timestampProtocolToDb({ t_s: 1742909388, - }, - stampExpireLegal: { + }), + stampExpireLegal: timestampProtocolToDb({ t_s: 1900589388, - }, - stampExpireWithdraw: { + }), + stampExpireWithdraw: timestampProtocolToDb({ t_s: 1679837388, - }, - stampStart: { + }), + stampStart: timestampProtocolToDb({ t_s: 1585229388, - }, + }), verificationStatus: DenominationVerificationStatus.Unverified, value: "KUDOS:5", currency: "KUDOS", - listIssueDate: { t_s: 0 }, + listIssueDate: timestampProtocolToDb({ t_s: 0 }), }, { denomPub: { @@ -228,22 +232,22 @@ test("withdrawal selection bug repro", (t) => { isRevoked: false, masterSig: "E3AWGAG8VB42P3KXM8B04Z6M483SX59R3Y4T53C3NXCA2NPB6C7HVCMVX05DC6S58E9X40NGEBQNYXKYMYCF3ASY2C4WP1WCZ4ME610", - stampExpireDeposit: { + stampExpireDeposit: timestampProtocolToDb({ t_s: 1742909388, - }, - stampExpireLegal: { + }), + stampExpireLegal: timestampProtocolToDb({ t_s: 1900589388, - }, - stampExpireWithdraw: { + }), + stampExpireWithdraw: timestampProtocolToDb({ t_s: 1679837388, - }, - stampStart: { + }), + stampStart: timestampProtocolToDb({ t_s: 1585229388, - }, + }), verificationStatus: DenominationVerificationStatus.Unverified, value: "KUDOS:1", currency: "KUDOS", - listIssueDate: { t_s: 0 }, + listIssueDate: timestampProtocolToDb({ t_s: 0 }), }, { denomPub: { @@ -282,18 +286,18 @@ test("withdrawal selection bug repro", (t) => { isRevoked: false, masterSig: "0ES1RKV002XB4YP21SN0QB7RSDHGYT0XAE65JYN8AVJAA6H7JZFN7JADXT521DJS89XMGPZGR8GCXF1516Y0Q9QDV00E6NMFA6CF838", - stampExpireDeposit: { + stampExpireDeposit: timestampProtocolToDb({ t_s: 1742909388, - }, - stampExpireLegal: { + }), + stampExpireLegal: timestampProtocolToDb({ t_s: 1900589388, - }, - stampExpireWithdraw: { + }), + stampExpireWithdraw: timestampProtocolToDb({ t_s: 1679837388, - }, - stampStart: { + }), + stampStart: timestampProtocolToDb({ t_s: 1585229388, - }, + }), verificationStatus: DenominationVerificationStatus.Unverified, value: Amounts.stringify({ currency: "KUDOS", @@ -301,7 +305,7 @@ test("withdrawal selection bug repro", (t) => { value: 0, }), currency: "KUDOS", - listIssueDate: { t_s: 0 }, + listIssueDate: timestampProtocolToDb({ t_s: 0 }), }, { denomPub: { @@ -340,22 +344,22 @@ test("withdrawal selection bug repro", (t) => { isRevoked: false, masterSig: "58QEB6C6N7602E572E3JYANVVJ9BRW0V9E2ZFDW940N47YVQDK9SAFPWBN5YGT3G1742AFKQ0CYR4DM2VWV0Z0T1XMEKWN6X2EZ9M0R", - stampExpireDeposit: { + stampExpireDeposit: timestampProtocolToDb({ t_s: 1742909388, - }, - stampExpireLegal: { + }), + stampExpireLegal: timestampProtocolToDb({ t_s: 1900589388, - }, - stampExpireWithdraw: { + }), + stampExpireWithdraw: timestampProtocolToDb({ t_s: 1679837388, - }, - stampStart: { + }), + stampStart: timestampProtocolToDb({ t_s: 1585229388, - }, + }), verificationStatus: DenominationVerificationStatus.Unverified, value: "KUDOS:2", currency: "KUDOS", - listIssueDate: { t_s: 0 }, + listIssueDate: timestampProtocolToDb({ t_s: 0 }), }, ]; diff --git a/packages/taler-wallet-core/src/pending-types.ts b/packages/taler-wallet-core/src/pending-types.ts index 627888b4d..e7a40e81b 100644 --- a/packages/taler-wallet-core/src/pending-types.ts +++ b/packages/taler-wallet-core/src/pending-types.ts @@ -25,7 +25,7 @@ * Imports. */ import { TalerErrorDetail, AbsoluteTime } from "@gnu-taler/taler-util"; -import { RetryInfo } from "./operations/common.js"; +import { DbRetryInfo } from "./operations/common.js"; export enum PendingTaskType { ExchangeUpdate = "exchange-update", @@ -137,7 +137,7 @@ export interface PendingRefreshTask { lastError?: TalerErrorDetail; refreshGroupId: string; finishedPerCoin: boolean[]; - retryInfo?: RetryInfo; + retryInfo?: DbRetryInfo; } /** @@ -156,7 +156,7 @@ export interface PendingTipPickupTask { export interface PendingPurchaseTask { type: PendingTaskType.Purchase; proposalId: string; - retryInfo?: RetryInfo; + retryInfo?: DbRetryInfo; /** * Status of the payment as string, used only for debugging. */ @@ -167,7 +167,7 @@ export interface PendingPurchaseTask { export interface PendingRecoupTask { type: PendingTaskType.Recoup; recoupGroupId: string; - retryInfo?: RetryInfo; + retryInfo?: DbRetryInfo; lastError: TalerErrorDetail | undefined; } @@ -177,7 +177,7 @@ export interface PendingRecoupTask { export interface PendingWithdrawTask { type: PendingTaskType.Withdraw; lastError: TalerErrorDetail | undefined; - retryInfo?: RetryInfo; + retryInfo?: DbRetryInfo; withdrawalGroupId: string; } @@ -187,7 +187,7 @@ export interface PendingWithdrawTask { export interface PendingDepositTask { type: PendingTaskType.Deposit; lastError: TalerErrorDetail | undefined; - retryInfo: RetryInfo | undefined; + retryInfo: DbRetryInfo | undefined; depositGroupId: string; } @@ -233,7 +233,7 @@ export interface PendingTaskInfoCommon { * Retry info. Currently used to stop the wallet after any operation * exceeds a number of retries. */ - retryInfo?: RetryInfo; + retryInfo?: DbRetryInfo; } /** diff --git a/packages/taler-wallet-core/src/util/denominations.ts b/packages/taler-wallet-core/src/util/denominations.ts index 76716cf7a..db6e69956 100644 --- a/packages/taler-wallet-core/src/util/denominations.ts +++ b/packages/taler-wallet-core/src/util/denominations.ts @@ -26,10 +26,9 @@ import { FeeDescriptionPair, TalerProtocolTimestamp, TimePoint, - WireFee, } from "@gnu-taler/taler-util"; import { DenominationRecord } from "../db.js"; -import { WalletConfig } from "../index.js"; +import { timestampProtocolFromDb } from "../index.js"; /** * Given a list of denominations with the same value and same period of time: @@ -457,9 +456,11 @@ export function isWithdrawableDenom( denomselAllowLate?: boolean, ): boolean { const now = AbsoluteTime.now(); - const start = AbsoluteTime.fromProtocolTimestamp(d.stampStart); + const start = AbsoluteTime.fromProtocolTimestamp( + timestampProtocolFromDb(d.stampStart), + ); const withdrawExpire = AbsoluteTime.fromProtocolTimestamp( - d.stampExpireWithdraw, + timestampProtocolFromDb(d.stampExpireWithdraw), ); const started = AbsoluteTime.cmp(now, start) >= 0; let lastPossibleWithdraw: AbsoluteTime; diff --git a/packages/taler-wallet-core/src/util/instructedAmountConversion.ts b/packages/taler-wallet-core/src/util/instructedAmountConversion.ts index 54c08eee4..a0394a687 100644 --- a/packages/taler-wallet-core/src/util/instructedAmountConversion.ts +++ b/packages/taler-wallet-core/src/util/instructedAmountConversion.ts @@ -14,6 +14,7 @@ GNU Taler; see the file COPYING. If not, see */ +import { GlobalIDB } from "@gnu-taler/idb-bridge"; import { AbsoluteTime, AgeRestriction, @@ -29,14 +30,14 @@ import { parsePaytoUri, strcmp, } from "@gnu-taler/taler-util"; -import { checkDbInvariant } from "./invariants.js"; import { DenominationRecord, InternalWalletState, getExchangeDetails, + timestampProtocolFromDb, } from "../index.js"; import { CoinInfo } from "./coinSelection.js"; -import { GlobalIDB } from "@gnu-taler/idb-bridge"; +import { checkDbInvariant } from "./invariants.js"; /** * If the operation going to be plan subtracts @@ -224,10 +225,10 @@ async function getAvailableDenoms( ); for (const denom of ds) { const expiresWithdraw = AbsoluteTime.fromProtocolTimestamp( - denom.stampExpireWithdraw, + timestampProtocolFromDb(denom.stampExpireWithdraw), ); const expiresDeposit = AbsoluteTime.fromProtocolTimestamp( - denom.stampExpireDeposit, + timestampProtocolFromDb(denom.stampExpireDeposit), ); creditDeadline = AbsoluteTime.min(deadline, expiresWithdraw); debitDeadline = AbsoluteTime.min(deadline, expiresDeposit); @@ -270,10 +271,10 @@ async function getAvailableDenoms( continue; } const expiresWithdraw = AbsoluteTime.fromProtocolTimestamp( - denom.stampExpireWithdraw, + timestampProtocolFromDb(denom.stampExpireWithdraw), ); const expiresDeposit = AbsoluteTime.fromProtocolTimestamp( - denom.stampExpireDeposit, + timestampProtocolFromDb(denom.stampExpireDeposit), ); creditDeadline = AbsoluteTime.min(deadline, expiresWithdraw); debitDeadline = AbsoluteTime.min(deadline, expiresDeposit); @@ -318,7 +319,9 @@ function buildCoinInfoFromDenom( exchangeBaseUrl: denom.exchangeBaseUrl, duration: AbsoluteTime.difference( AbsoluteTime.now(), - AbsoluteTime.fromProtocolTimestamp(denom.stampExpireDeposit), + AbsoluteTime.fromProtocolTimestamp( + timestampProtocolFromDb(denom.stampExpireDeposit), + ), ), totalAvailable: total, value: Amounts.parseOrThrow(denom.value), -- cgit v1.2.3 From 93e0f26b432a0e96d9f50e58058bb69d7fbf74e8 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 14 Sep 2023 17:43:20 +0200 Subject: -remove unused record --- packages/taler-wallet-core/src/db.ts | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 4fc6db68a..597cdf5a5 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -582,25 +582,6 @@ export interface ExchangeDetailsRecord { ageMask?: number; } -export interface ExchangeTosRecord { - exchangeBaseUrl: string; - - etag: string; - - /** - * Terms of service text or undefined if not downloaded yet. - * - * This is just used as a cache of the last downloaded ToS. - * - */ - termsOfServiceText: string | undefined; - - /** - * Content-type of the last downloaded termsOfServiceText. - */ - termsOfServiceContentType: string | undefined; -} - export interface ExchangeDetailsPointer { masterPublicKey: string; -- cgit v1.2.3 From c919c30ef3c5a2988823e4d76c8e22067db88804 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 14 Sep 2023 20:58:40 +0200 Subject: -formatting, don't use deprecated method --- packages/taler-wallet-core/src/wallet.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 2d0878afc..9091a92bf 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -923,9 +923,9 @@ async function dumpCoins(ws: InternalWalletState): Promise { ageCommitmentProof: c.ageCommitmentProof, spend_allocation: c.spendAllocation ? { - amount: c.spendAllocation.amount, - id: c.spendAllocation.id, - } + amount: c.spendAllocation.amount, + id: c.spendAllocation.id, + } : undefined, }); } @@ -1261,7 +1261,10 @@ async function dispatchRequestInternal( `templates/${url.templateId}`, url.merchantBaseUrl, ); - const httpReq = await ws.http.postJson(reqUrl.href, templateDetails); + const httpReq = await ws.http.fetch(reqUrl.href, { + method: "POST", + body: templateDetails, + }); const resp = await readSuccessResponseJsonOrThrow( httpReq, codecForMerchantPostOrderResponse(), -- cgit v1.2.3 From 5de329e653bb1e2a0b6ad8247cb76d285a98fdc0 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 15 Sep 2023 12:51:57 +0200 Subject: wallet-core: fix type error in purse_expiration --- .../src/integrationtests/test-peer-to-peer-pull.ts | 4 +- .../src/integrationtests/test-wallet-gendb.ts | 110 +++++++++++++++++++++ .../src/integrationtests/testrunner.ts | 2 + .../src/operations/pay-peer-pull-credit.ts | 2 +- .../src/operations/pay-peer-push-debit.ts | 5 +- 5 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 packages/taler-harness/src/integrationtests/test-wallet-gendb.ts (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts b/packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts index 25c000808..6d9f44fb5 100644 --- a/packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts +++ b/packages/taler-harness/src/integrationtests/test-peer-to-peer-pull.ts @@ -73,7 +73,7 @@ export async function runPeerToPeerPullTest(t: GlobalTestState) { await withdrawRes.withdrawalFinishedCond; - const purse_expiration = AbsoluteTime.toProtocolTimestamp( + const purseExpiration = AbsoluteTime.toProtocolTimestamp( AbsoluteTime.addDuration( AbsoluteTime.now(), Duration.fromSpec({ days: 2 }), @@ -87,7 +87,7 @@ export async function runPeerToPeerPullTest(t: GlobalTestState) { partialContractTerms: { summary: "Hello World", amount: "TESTKUDOS:5", - purse_expiration, + purse_expiration: purseExpiration, }, }, ); diff --git a/packages/taler-harness/src/integrationtests/test-wallet-gendb.ts b/packages/taler-harness/src/integrationtests/test-wallet-gendb.ts new file mode 100644 index 000000000..ff6ed9959 --- /dev/null +++ b/packages/taler-harness/src/integrationtests/test-wallet-gendb.ts @@ -0,0 +1,110 @@ +/* + 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 + */ + +/** + * Imports. + */ +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { GlobalTestState } from "../harness/harness.js"; +import { + createSimpleTestkudosEnvironmentV2, + withdrawViaBankV2, + makeTestPaymentV2, +} from "../harness/helpers.js"; +import { + AbsoluteTime, + Duration, + NotificationType, + TransactionMajorState, + TransactionMinorState, + j2s, +} from "@gnu-taler/taler-util"; + +/** + * Test that creates various transactions and exports the resulting + * database. Used to generate a database export file for DB compatibility + * testing. + */ +export async function runWalletGenDbTest(t: GlobalTestState) { + // Set up test environment + + const { walletClient, bank, exchange, merchant } = + await createSimpleTestkudosEnvironmentV2(t); + + // Withdraw digital cash into the wallet. + + await withdrawViaBankV2(t, { + walletClient, + bank, + exchange, + amount: "TESTKUDOS:50", + }); + + await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); + + const order = { + summary: "Buy me!", + amount: "TESTKUDOS:10", + fulfillment_url: "taler://fulfillment-success/thx", + }; + + await makeTestPaymentV2(t, { walletClient, merchant, order }); + await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); + + const purseExpiration = AbsoluteTime.toProtocolTimestamp( + AbsoluteTime.addDuration( + AbsoluteTime.now(), + Duration.fromSpec({ days: 2 }), + ), + ); + + const peerPullIniResp = await walletClient.call( + WalletApiOperation.InitiatePeerPullCredit, + { + exchangeBaseUrl: exchange.baseUrl, + partialContractTerms: { + summary: "Hello World", + amount: "TESTKUDOS:5", + purse_expiration: purseExpiration, + }, + }, + ); + + const peerPullCreditReadyCond = walletClient.waitForNotificationCond( + (x) => + x.type === NotificationType.TransactionStateTransition && + x.transactionId === peerPullIniResp.transactionId && + x.newTxState.major === TransactionMajorState.Pending && + x.newTxState.minor === TransactionMinorState.Ready, + ); + + await peerPullCreditReadyCond; + + const checkResp = await walletClient.call( + WalletApiOperation.PreparePeerPullDebit, + { + talerUri: peerPullIniResp.talerUri, + }, + ); + + await walletClient.call(WalletApiOperation.ConfirmPeerPullDebit, { + transactionId: checkResp.transactionId, + }); + + await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); +} + +runWalletGenDbTest.suites = ["wallet"]; diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts index 66bd87a59..237d3bf9f 100644 --- a/packages/taler-harness/src/integrationtests/testrunner.ts +++ b/packages/taler-harness/src/integrationtests/testrunner.ts @@ -110,6 +110,7 @@ import { runWithdrawalFakebankTest } from "./test-withdrawal-fakebank.js"; import { runWithdrawalFeesTest } from "./test-withdrawal-fees.js"; import { runWithdrawalHugeTest } from "./test-withdrawal-huge.js"; import { runWithdrawalManualTest } from "./test-withdrawal-manual.js"; +import { runWalletGenDbTest } from "./test-wallet-gendb.js"; /** * Test runner. @@ -209,6 +210,7 @@ const allTests: TestMainFunction[] = [ runTermOfServiceFormatTest, runStoredBackupsTest, runPaymentExpiredTest, + runWalletGenDbTest, ]; export interface TestRunSpec { diff --git a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts index 6ec8822ab..54b78957f 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer-pull-credit.ts @@ -392,7 +392,7 @@ async function handlePeerPullCreditCreatePurse( const econtractResp = await ws.cryptoApi.encryptContractForDeposit({ contractPriv: pullIni.contractPriv, contractPub: pullIni.contractPub, - contractTerms: contractTermsRecord, + contractTerms: contractTermsRecord.contractTermsRaw, pursePriv: pullIni.pursePriv, pursePub: pullIni.pursePub, nonce: pullIni.contractEncNonce, diff --git a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts index a7b9f79eb..50ae8d41b 100644 --- a/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts +++ b/packages/taler-wallet-core/src/operations/pay-peer-push-debit.ts @@ -245,8 +245,6 @@ async function processPeerPushDebitCreateReserve( hash(decodeCrock(econtractResp.econtract.econtract)), ); - logger.info(`econtract hash: ${econtractHash}`); - const createPurseUrl = new URL( `purses/${peerPushInitiation.pursePub}/create`, peerPushInitiation.exchangeBaseUrl, @@ -257,7 +255,7 @@ async function processPeerPushDebitCreateReserve( merge_pub: peerPushInitiation.mergePub, purse_sig: purseSigResp.sig, h_contract_terms: hContractTerms, - purse_expiration: purseExpiration, + purse_expiration: timestampProtocolFromDb(purseExpiration), deposits: depositSigsResp.deposits, min_age: 0, econtract: econtractResp.econtract, @@ -649,7 +647,6 @@ export async function initiatePeerPushDebit( // we might want to mark the coins as used and spend them // after we've been able to create the purse. await spendCoins(ws, tx, { - // allocationId: `txn:peer-push-debit:${pursePair.pub}`, allocationId: constructTransactionIdentifier({ tag: TransactionType.PeerPushDebit, pursePub: pursePair.pub, -- cgit v1.2.3 From de117e375a2a3cfa312acf4176276092f55205e0 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 15 Sep 2023 13:35:47 +0200 Subject: wallet-core: make planchets.byGroupAndIndex unique --- packages/taler-wallet-core/src/db.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 597cdf5a5..a5ead4d64 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -2434,10 +2434,13 @@ export const WalletStoresV1 = { "planchets", describeContents({ keyPath: "coinPub" }), { - byGroupAndIndex: describeIndex("byGroupAndIndex", [ - "withdrawalGroupId", - "coinIdx", - ]), + byGroupAndIndex: describeIndex( + "byGroupAndIndex", + ["withdrawalGroupId", "coinIdx"], + { + unique: true, + }, + ), byGroup: describeIndex("byGroup", "withdrawalGroupId"), byCoinEvHash: describeIndex("byCoinEv", "coinEvHash"), }, -- cgit v1.2.3 From a15eec55d3136b4f737c68ac41e3042624b8e25f Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 15 Sep 2023 16:45:12 +0200 Subject: wallet-core: correctly consider deposit fee in p2p coin selection --- .../src/util/coinSelection.test.ts | 209 +++++++++++---------- .../taler-wallet-core/src/util/coinSelection.ts | 24 ++- 2 files changed, 127 insertions(+), 106 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/util/coinSelection.test.ts b/packages/taler-wallet-core/src/util/coinSelection.test.ts index f809c4e60..81a656f8a 100644 --- a/packages/taler-wallet-core/src/util/coinSelection.test.ts +++ b/packages/taler-wallet-core/src/util/coinSelection.test.ts @@ -15,49 +15,58 @@ */ import { AbsoluteTime, - AgeRestriction, - AmountJson, AmountString, Amounts, DenomKeyType, Duration, - TransactionAmountMode, + j2s, } from "@gnu-taler/taler-util"; import test, { ExecutionContext } from "ava"; -import { AvailableDenom, testing_greedySelectPeer, testing_selectGreedy } from "./coinSelection.js" +import { + AvailableDenom, + testing_greedySelectPeer, + testing_selectGreedy, +} from "./coinSelection.js"; const inTheDistantFuture = AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.addDuration(AbsoluteTime.now(), Duration.fromSpec({ hours: 1 })) -) + AbsoluteTime.addDuration(AbsoluteTime.now(), Duration.fromSpec({ hours: 1 })), +); const inThePast = AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.subtractDuraction(AbsoluteTime.now(), Duration.fromSpec({ hours: 1 })) -) + AbsoluteTime.subtractDuraction( + AbsoluteTime.now(), + Duration.fromSpec({ hours: 1 }), + ), +); test("p2p: should select the coin", (t) => { - const instructedAmount = Amounts.parseOrThrow("LOCAL:2") + const instructedAmount = Amounts.parseOrThrow("LOCAL:2"); const tally = { amountAcc: Amounts.zeroOfCurrency(instructedAmount.currency), depositFeesAcc: Amounts.zeroOfCurrency(instructedAmount.currency), lastDepositFee: Amounts.zeroOfCurrency(instructedAmount.currency), }; const coins = testing_greedySelectPeer( - createCandidates([{ - amount: "LOCAL:10", - numAvailable: 5, - depositFee: "LOCAL:0.1", - fromExchange: "http://exchange.localhost/", - }]), - instructedAmount, - tally + createCandidates([ + { + amount: "LOCAL:10", + numAvailable: 5, + depositFee: "LOCAL:0.1", + fromExchange: "http://exchange.localhost/", + }, + ]), + instructedAmount, + tally, ); + t.log(j2s(coins)); + expect(t, coins).deep.equal({ "hash0;32;http://exchange.localhost/": { exchangeBaseUrl: "http://exchange.localhost/", denomPubHash: "hash0", maxAge: 32, - contributions: [Amounts.parseOrThrow("LOCAL:2")], - } + contributions: [Amounts.parseOrThrow("LOCAL:2.1")], + }, }); expect(t, tally).deep.equal({ @@ -65,25 +74,26 @@ test("p2p: should select the coin", (t) => { depositFeesAcc: Amounts.parseOrThrow("LOCAL:0.1"), lastDepositFee: Amounts.parseOrThrow("LOCAL:0.1"), }); - }); test("p2p: should select 3 coins", (t) => { - const instructedAmount = Amounts.parseOrThrow("LOCAL:20") + const instructedAmount = Amounts.parseOrThrow("LOCAL:20"); const tally = { amountAcc: Amounts.zeroOfCurrency(instructedAmount.currency), depositFeesAcc: Amounts.zeroOfCurrency(instructedAmount.currency), lastDepositFee: Amounts.zeroOfCurrency(instructedAmount.currency), }; const coins = testing_greedySelectPeer( - createCandidates([{ - amount: "LOCAL:10", - numAvailable: 5, - depositFee: "LOCAL:0.1", - fromExchange: "http://exchange.localhost/", - }]), - instructedAmount, - tally + createCandidates([ + { + amount: "LOCAL:10", + numAvailable: 5, + depositFee: "LOCAL:0.1", + fromExchange: "http://exchange.localhost/", + }, + ]), + instructedAmount, + tally, ); expect(t, coins).deep.equal({ @@ -94,9 +104,9 @@ test("p2p: should select 3 coins", (t) => { contributions: [ Amounts.parseOrThrow("LOCAL:9.9"), Amounts.parseOrThrow("LOCAL:9.9"), - Amounts.parseOrThrow("LOCAL:0.2") + Amounts.parseOrThrow("LOCAL:0.5"), ], - } + }, }); expect(t, tally).deep.equal({ @@ -104,41 +114,41 @@ test("p2p: should select 3 coins", (t) => { depositFeesAcc: Amounts.parseOrThrow("LOCAL:0.3"), lastDepositFee: Amounts.parseOrThrow("LOCAL:0.1"), }); - }); test("p2p: can't select since the instructed amount is too high", (t) => { - const instructedAmount = Amounts.parseOrThrow("LOCAL:60") + const instructedAmount = Amounts.parseOrThrow("LOCAL:60"); const tally = { amountAcc: Amounts.zeroOfCurrency(instructedAmount.currency), depositFeesAcc: Amounts.zeroOfCurrency(instructedAmount.currency), lastDepositFee: Amounts.zeroOfCurrency(instructedAmount.currency), }; const coins = testing_greedySelectPeer( - createCandidates([{ - amount: "LOCAL:10", - numAvailable: 5, - depositFee: "LOCAL:0.1", - fromExchange: "http://exchange.localhost/", - }]), - instructedAmount, - tally + createCandidates([ + { + amount: "LOCAL:10", + numAvailable: 5, + depositFee: "LOCAL:0.1", + fromExchange: "http://exchange.localhost/", + }, + ]), + instructedAmount, + tally, ); expect(t, coins).deep.equal(undefined); expect(t, tally).deep.equal({ - amountAcc: Amounts.parseOrThrow("LOCAL:49.5"), + amountAcc: Amounts.parseOrThrow("LOCAL:49"), depositFeesAcc: Amounts.parseOrThrow("LOCAL:0.5"), lastDepositFee: Amounts.parseOrThrow("LOCAL:0.1"), }); - }); test("pay: select one coin to pay with fee", (t) => { - const payment = Amounts.parseOrThrow("LOCAL:2") - const exchangeWireFee = Amounts.parseOrThrow("LOCAL:0.1") - const zero = Amounts.zeroOfCurrency(payment.currency) + const payment = Amounts.parseOrThrow("LOCAL:2"); + const exchangeWireFee = Amounts.parseOrThrow("LOCAL:0.1"); + const zero = Amounts.zeroOfCurrency(payment.currency); const tally = { amountPayRemaining: payment, amountWireFeeLimitRemaining: zero, @@ -150,28 +160,30 @@ test("pay: select one coin to pay with fee", (t) => { }; const coins = testing_selectGreedy( { - "auditors": [], - "exchanges": [ - { - "exchangeBaseUrl": "http://exchange.localhost/", - "exchangePub": "E5M8CGRDHXF1RCVP3B8TQCTDYNQ7T4XHWR5SVEQRGVVMVME41VJ0" - } + auditors: [], + exchanges: [ + { + exchangeBaseUrl: "http://exchange.localhost/", + exchangePub: "E5M8CGRDHXF1RCVP3B8TQCTDYNQ7T4XHWR5SVEQRGVVMVME41VJ0", + }, ], - "contractTermsAmount": payment, - "depositFeeLimit": zero, - "wireFeeAmortization": 1, - "wireFeeLimit": zero, - "prevPayCoins": [], - "wireMethod": "x-taler-bank" + contractTermsAmount: payment, + depositFeeLimit: zero, + wireFeeAmortization: 1, + wireFeeLimit: zero, + prevPayCoins: [], + wireMethod: "x-taler-bank", }, - createCandidates([{ - amount: "LOCAL:10", - numAvailable: 5, - depositFee: "LOCAL:0.1", - fromExchange: "http://exchange.localhost/", - }]), - {"http://exchange.localhost/": exchangeWireFee}, - tally + createCandidates([ + { + amount: "LOCAL:10", + numAvailable: 5, + depositFee: "LOCAL:0.1", + fromExchange: "http://exchange.localhost/", + }, + ]), + { "http://exchange.localhost/": exchangeWireFee }, + tally, ); expect(t, coins).deep.equal({ @@ -179,10 +191,8 @@ test("pay: select one coin to pay with fee", (t) => { exchangeBaseUrl: "http://exchange.localhost/", denomPubHash: "hash0", maxAge: 32, - contributions: [ - Amounts.parseOrThrow("LOCAL:2.2"), - ], - } + contributions: [Amounts.parseOrThrow("LOCAL:2.2")], + }, }); expect(t, tally).deep.equal({ @@ -194,44 +204,46 @@ test("pay: select one coin to pay with fee", (t) => { wireFeeCoveredForExchange: new Set(), lastDepositFee: zero, }); - }); - - - -function createCandidates(ar: {amount: AmountString, depositFee: AmountString, numAvailable: number, fromExchange: string}[]): AvailableDenom[] { - return ar.map((r,idx) => { +function createCandidates( + ar: { + amount: AmountString; + depositFee: AmountString; + numAvailable: number; + fromExchange: string; + }[], +): AvailableDenom[] { + return ar.map((r, idx) => { return { - "denomPub": { - "age_mask": 0, - "cipher": DenomKeyType.Rsa, - "rsa_public_key": "PPP" + denomPub: { + age_mask: 0, + cipher: DenomKeyType.Rsa, + rsa_public_key: "PPP", }, - "denomPubHash": `hash${idx}`, - "value": r.amount, - "feeDeposit": r.depositFee, - "feeRefresh": "LOCAL:0", - "feeRefund": "LOCAL:0", - "feeWithdraw": "LOCAL:0", - "stampExpireDeposit": inTheDistantFuture, - "stampExpireLegal": inTheDistantFuture, - "stampExpireWithdraw": inTheDistantFuture, - "stampStart": inThePast, - "exchangeBaseUrl": r.fromExchange, - "numAvailable": r.numAvailable, - "maxAge": 32, - - } - }) + denomPubHash: `hash${idx}`, + value: r.amount, + feeDeposit: r.depositFee, + feeRefresh: "LOCAL:0", + feeRefund: "LOCAL:0", + feeWithdraw: "LOCAL:0", + stampExpireDeposit: inTheDistantFuture, + stampExpireLegal: inTheDistantFuture, + stampExpireWithdraw: inTheDistantFuture, + stampStart: inThePast, + exchangeBaseUrl: r.fromExchange, + numAvailable: r.numAvailable, + maxAge: 32, + }; + }); } type Tester = { deep: { equal(another: T): ReturnType; equals(another: T): ReturnType; - } -} + }; +}; function expect(t: ExecutionContext, thing: T): Tester { return { @@ -241,4 +253,3 @@ function expect(t: ExecutionContext, thing: T): Tester { }, }; } - diff --git a/packages/taler-wallet-core/src/util/coinSelection.ts b/packages/taler-wallet-core/src/util/coinSelection.ts index 0b1be881f..8c90f26f1 100644 --- a/packages/taler-wallet-core/src/util/coinSelection.ts +++ b/packages/taler-wallet-core/src/util/coinSelection.ts @@ -419,8 +419,10 @@ interface SelResult { }; } -export function testing_selectGreedy(...args: Parameters): ReturnType{ - return selectGreedy(...args) +export function testing_selectGreedy( + ...args: Parameters +): ReturnType { + return selectGreedy(...args); } function selectGreedy( req: SelectPayCoinRequestNg, @@ -900,9 +902,12 @@ interface PeerCoinSelectionTally { /** * exporting for testing */ -export function testing_greedySelectPeer(...args: Parameters): ReturnType { - return greedySelectPeer(...args) +export function testing_greedySelectPeer( + ...args: Parameters +): ReturnType { + return greedySelectPeer(...args); } + function greedySelectPeer( candidates: AvailableDenom[], instructedAmount: AmountLike, @@ -921,11 +926,16 @@ function greedySelectPeer( instructedAmount, tally.amountAcc, ).amount; - const coinContrib = Amounts.sub(denom.value, denom.feeDeposit).amount + // Maximum amount the coin could effectively contribute. + const maxCoinContrib = Amounts.sub(denom.value, denom.feeDeposit).amount; + + const coinSpend = Amounts.min( + Amounts.add(amountPayRemaining, denom.feeDeposit).amount, + maxCoinContrib, + ); - const coinSpend = Amounts.min(amountPayRemaining, coinContrib) - tally.amountAcc = Amounts.add(tally.amountAcc, coinSpend).amount; + tally.amountAcc = Amounts.sub(tally.amountAcc, denom.feeDeposit).amount; tally.depositFeesAcc = Amounts.add( tally.depositFeesAcc, -- cgit v1.2.3 From 0ff189d229b348422239670223b4944b42596f63 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 15 Sep 2023 17:04:44 +0200 Subject: wallet-core: fix tipping --- packages/taler-util/src/MerchantApiClient.ts | 2 +- packages/taler-wallet-core/src/dbless.ts | 5 ++++- packages/taler-wallet-core/src/operations/reward.ts | 7 +++++-- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-util/src/MerchantApiClient.ts b/packages/taler-util/src/MerchantApiClient.ts index ccbbf79b3..988872ae7 100644 --- a/packages/taler-util/src/MerchantApiClient.ts +++ b/packages/taler-util/src/MerchantApiClient.ts @@ -269,7 +269,7 @@ export class MerchantApiClient { } async giveTip(req: RewardCreateRequest): Promise { - const reqUrl = new URL(`private/tips`, this.baseUrl); + const reqUrl = new URL(`private/rewards`, this.baseUrl); const resp = await this.httpClient.fetch(reqUrl.href, { method: "POST", body: req, diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts index d70eab888..4d2fa5cd4 100644 --- a/packages/taler-wallet-core/src/dbless.ts +++ b/packages/taler-wallet-core/src/dbless.ts @@ -276,7 +276,10 @@ export async function depositCoin(args: { merchant_pub: merchantPub, }; const url = new URL(`batch-deposit`, dp.exchange_url); - const httpResp = await http.fetch(url.href, { body: requestBody }); + const httpResp = await http.fetch(url.href, { + method: "POST", + body: requestBody, + }); await readSuccessResponseJsonOrThrow(httpResp, codecForBatchDepositSuccess()); } diff --git a/packages/taler-wallet-core/src/operations/reward.ts b/packages/taler-wallet-core/src/operations/reward.ts index ddcfb20ac..4e16d977d 100644 --- a/packages/taler-wallet-core/src/operations/reward.ts +++ b/packages/taler-wallet-core/src/operations/reward.ts @@ -304,13 +304,16 @@ export async function processTip( } const tipStatusUrl = new URL( - `tips/${tipRecord.merchantRewardId}/pickup`, + `rewards/${tipRecord.merchantRewardId}/pickup`, tipRecord.merchantBaseUrl, ); const req = { planchets: planchetsDetail }; logger.trace(`sending tip request: ${j2s(req)}`); - const merchantResp = await ws.http.postJson(tipStatusUrl.href, req); + const merchantResp = await ws.http.fetch(tipStatusUrl.href, { + method: "POST", + body: req, + }); logger.trace(`got tip response, status ${merchantResp.status}`); -- cgit v1.2.3 From 40d2aa0c11e61ea45005c4c212c6ab686162b4b0 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 15 Sep 2023 17:14:37 +0200 Subject: cli: allow DB stats tracking via environment variable --- packages/taler-wallet-cli/src/index.ts | 38 +++++++++++++++--------- packages/taler-wallet-core/src/host-impl.node.ts | 5 +++- 2 files changed, 28 insertions(+), 15 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index 3fc86d0b5..b37d4974b 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -53,6 +53,7 @@ import { import { createPlatformHttpLib } from "@gnu-taler/taler-util/http"; import { JsonMessage, runRpcServer } from "@gnu-taler/taler-util/twrpc"; import { + AccessStats, createNativeWalletHost, createNativeWalletHost2, Wallet, @@ -237,16 +238,21 @@ export interface WalletContext { ): Promise; } +interface CreateWalletResult { + wallet: Wallet; + getStats: () => AccessStats; +} + async function createLocalWallet( walletCliArgs: WalletCliArgsType, notificationHandler?: (n: WalletNotification) => void, -): Promise { +): Promise { const dbPath = walletCliArgs.wallet.walletDbFile ?? defaultWalletDbPath; const myHttpLib = createPlatformHttpLib({ enableThrottling: walletCliArgs.wallet.noThrottle ? false : true, requireTls: walletCliArgs.wallet.noHttp, }); - const wallet = await createNativeWalletHost({ + const wh = await createNativeWalletHost2({ persistentStoragePath: dbPath !== ":memory:" ? dbPath : undefined, httpLib: myHttpLib, notifyHandler: (n) => { @@ -269,10 +275,10 @@ async function createLocalWallet( applyVerbose(walletCliArgs.wallet.verbose); try { - await wallet.handleCoreApiRequest("initWallet", "native-init", { + await wh.wallet.handleCoreApiRequest("initWallet", "native-init", { skipDefaults: walletCliArgs.wallet.skipDefaults, }); - return wallet; + return { wallet: wh.wallet, getStats: wh.getDbStats }; } catch (e) { const ed = getErrorDetailFromException(e); console.error("Operation failed: " + summarizeTalerErrorDetail(ed)); @@ -307,16 +313,20 @@ async function withWallet( w.close(); return res; } else { - const w = await createLocalWallet(walletCliArgs, waiter.notify); + const wh = await createLocalWallet(walletCliArgs, waiter.notify); const ctx: WalletContext = { - client: w.client, + client: wh.wallet.client, waitForNotificationCond: waiter.waitForNotificationCond, makeCoreApiRequest(operation, payload) { - return w.handleCoreApiRequest(operation, "my-req", payload); + return wh.wallet.handleCoreApiRequest(operation, "my-req", payload); }, }; const result = await f(ctx); - w.stop(); + wh.wallet.stop(); + if (process.env.TALER_WALLET_DBSTATS) { + console.log("database stats:"); + console.log(j2s(wh.getStats())); + } return result; } } @@ -330,7 +340,8 @@ async function withLocalWallet( walletCliArgs: WalletCliArgsType, f: (w: { client: WalletCoreApiClient; ws: Wallet }) => Promise, ): Promise { - const w = await createLocalWallet(walletCliArgs); + const wh = await createLocalWallet(walletCliArgs); + const w = wh.wallet; const res = await f({ client: w.client, ws: w }); w.stop(); return res; @@ -1030,8 +1041,7 @@ peerCli const resp = await wallet.client.call( WalletApiOperation.ConfirmPeerPullDebit, { - peerPullDebitId: - args.confirmIncomingPayPull.peerPullDebitId, + peerPullDebitId: args.confirmIncomingPayPull.peerPullDebitId, }, ); console.log(JSON.stringify(resp, undefined, 2)); @@ -1046,8 +1056,7 @@ peerCli const resp = await wallet.client.call( WalletApiOperation.ConfirmPeerPushCredit, { - peerPushCreditId: - args.confirmIncomingPayPush.peerPushCreditId, + peerPushCreditId: args.confirmIncomingPayPush.peerPushCreditId, }, ); console.log(JSON.stringify(resp, undefined, 2)); @@ -1174,7 +1183,8 @@ advancedCli }) .action(async (args) => { logger.info(`serving at ${args.serve.unixPath}`); - const w = await createLocalWallet(args); + const wh = await createLocalWallet(args); + const w = wh.wallet; w.runTaskLoop() .then((res) => { logger.warn("task loop exited unexpectedly"); diff --git a/packages/taler-wallet-core/src/host-impl.node.ts b/packages/taler-wallet-core/src/host-impl.node.ts index a6dae58a1..33162ec50 100644 --- a/packages/taler-wallet-core/src/host-impl.node.ts +++ b/packages/taler-wallet-core/src/host-impl.node.ts @@ -108,10 +108,13 @@ async function makeSqliteDb( filename: args.persistentStoragePath ?? ":memory:", }); myBackend.enableTracing = false; + if (process.env.TALER_WALLET_DBSTATS) { + myBackend.trackStats = true; + } const myBridgeIdbFactory = new BridgeIDBFactory(myBackend); return { getStats() { - throw Error("not implemented"); + return myBackend.accessStats; }, idbFactory: myBridgeIdbFactory, }; -- cgit v1.2.3 From 58debefbe0456ce203877f1cc417c42f4abb0685 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 21 Sep 2023 17:56:29 +0200 Subject: wallet-core,harness: towards corebank API instead of fakebank/nexus API --- packages/demobank-ui/src/hooks/access.ts | 1 + packages/taler-harness/src/harness/harness.ts | 11 +- packages/taler-harness/src/harness/helpers.ts | 4 +- .../taler-harness/src/harness/libeufin-apis.ts | 775 --------------- packages/taler-harness/src/harness/libeufin.ts | 1047 -------------------- packages/taler-harness/src/index.ts | 4 +- .../test-age-restrictions-merchant.ts | 4 +- .../src/integrationtests/test-bank-api.ts | 4 +- .../integrationtests/test-exchange-management.ts | 4 +- .../taler-harness/src/integrationtests/test-kyc.ts | 4 +- .../test-libeufin-api-bankaccount.ts | 108 -- .../test-libeufin-api-bankconnection.ts | 56 -- .../test-libeufin-api-facade-bad-request.ts | 68 -- .../integrationtests/test-libeufin-api-facade.ts | 70 -- .../test-libeufin-api-permissions.ts | 65 -- .../test-libeufin-api-sandbox-camt.ts | 76 -- .../test-libeufin-api-sandbox-transactions.ts | 69 -- .../test-libeufin-api-scheduling.ts | 106 -- .../integrationtests/test-libeufin-api-users.ts | 63 -- .../integrationtests/test-libeufin-bad-gateway.ts | 75 -- .../src/integrationtests/test-libeufin-basic.ts | 317 ------ .../src/integrationtests/test-libeufin-c5x.ts | 147 --- .../test-libeufin-facade-anastasis.ts | 179 ---- .../integrationtests/test-libeufin-keyrotation.ts | 82 -- .../test-libeufin-nexus-balance.ts | 117 --- .../test-libeufin-refund-multiple-users.ts | 104 -- .../src/integrationtests/test-libeufin-refund.ts | 101 -- .../test-libeufin-sandbox-wire-transfer-cli.ts | 85 -- .../src/integrationtests/test-libeufin-tutorial.ts | 130 --- .../src/integrationtests/test-payment-fault.ts | 4 +- .../src/integrationtests/test-tipping.ts | 4 +- .../integrationtests/test-wallet-notifications.ts | 4 +- .../integrationtests/test-withdrawal-abort-bank.ts | 4 +- .../test-withdrawal-bank-integrated.ts | 4 +- .../integrationtests/test-withdrawal-fakebank.ts | 5 +- .../src/integrationtests/test-withdrawal-fees.ts | 4 +- .../src/integrationtests/test-withdrawal-manual.ts | 4 +- .../src/integrationtests/testrunner.ts | 38 - packages/taler-util/src/bank-api-client.ts | 126 ++- packages/taler-util/src/wallet-types.ts | 8 +- packages/taler-wallet-core/src/dbless.ts | 4 +- .../taler-wallet-core/src/operations/testing.ts | 21 +- packages/taler-wallet-core/src/wallet.ts | 18 +- 43 files changed, 166 insertions(+), 3958 deletions(-) delete mode 100644 packages/taler-harness/src/harness/libeufin-apis.ts delete mode 100644 packages/taler-harness/src/harness/libeufin.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-api-bankaccount.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-api-bankconnection.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-api-facade-bad-request.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-api-facade.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-api-permissions.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-api-sandbox-camt.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-api-sandbox-transactions.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-api-scheduling.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-api-users.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-bad-gateway.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-basic.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-c5x.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-facade-anastasis.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-keyrotation.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-nexus-balance.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-refund-multiple-users.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-refund.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-sandbox-wire-transfer-cli.ts delete mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-tutorial.ts (limited to 'packages/taler-wallet-core') diff --git a/packages/demobank-ui/src/hooks/access.ts b/packages/demobank-ui/src/hooks/access.ts index b8b6ab899..61f458e51 100644 --- a/packages/demobank-ui/src/hooks/access.ts +++ b/packages/demobank-ui/src/hooks/access.ts @@ -124,6 +124,7 @@ export function useTestingAPI(): TestingAPI { const register = async ( data: SandboxBackend.Access.BankRegistrationRequest, ): Promise> => { + // FIXME: This API is deprecated. The normal account registration API should be used instead. const res = await noAuthRequest(`access-api/testing/register`, { method: "POST", data, diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts index 0c3c367af..edb0071c8 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, @@ -650,8 +650,7 @@ export class FakebankService } get bankAccessApiBaseUrl(): string { - let url = new URL("taler-bank-access/", this.baseUrl); - return url.href; + return this.baseUrl; } async createExchangeAccount( @@ -666,7 +665,7 @@ export class FakebankService accountName: accountName, accountPassword: password, accountPaytoUri: getPayto(accountName), - wireGatewayApiBaseUrl: `http://localhost:${this.bankConfig.httpPort}/taler-wire-gateway/${accountName}/`, + wireGatewayApiBaseUrl: `http://localhost:${this.bankConfig.httpPort}/accounts/${accountName}/taler-wire-gateway/`, }; } @@ -691,14 +690,14 @@ export class FakebankService "bank", ); await this.pingUntilAvailable(); - const bankClient = new BankAccessApiClient(this.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(this.bankAccessApiBaseUrl); for (const acc of this.accounts) { await bankClient.registerAccount(acc.accountName, acc.accountPassword); } } async pingUntilAvailable(): Promise { - 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"); } } diff --git a/packages/taler-harness/src/harness/helpers.ts b/packages/taler-harness/src/harness/helpers.ts index 9892e600b..0a864cad3 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, @@ -560,7 +560,7 @@ export async function withdrawViaBankV2( ): Promise { const { walletClient: wallet, bank, exchange, amount } = p; - const bankClient = new BankAccessApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); const user = await bankClient.createRandomBankUser(); const wop = await bankClient.createWithdrawalOperation(user.username, amount); 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 { - 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 { - // 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 - */ - -/** - * 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; -} - -export interface LibeufinNexusTransaction { - amount: string; - creditDebitIndicator: string; - status: string; - bankTransactionCode: string; - valueDate: string; - bookingDate: string; - accountServicerRef: string; - batches: Array; -} - -export interface LibeufinNexusTransactions { - transactions: Array; -} - -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 { - 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 { - 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 { - 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 { - 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 { - const url = this.baseUrl; - await pingProc(this.sandboxProc, url, "libeufin-sandbox"); - } -} - -export class LibeufinNexusService { - static async create( - gc: GlobalTestState, - nexusConfig: LibeufinNexusConfig, - ): Promise { - 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 { - 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 { - const url = `${this.baseUrl}config`; - await pingProc(this.nexusProc, url, "libeufin-nexus"); - } - - async createNexusSuperuser(details: LibeufinNexusUser): Promise { - 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 { - const stdout = await sh( - this.globalTestState, - "libeufin-cli-checksandbox", - "libeufin-cli sandbox check", - this.env(), - ); - } - - async registerBankCustomer( - username: string, - password: string, - ): Promise { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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; - } - } - } -} diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts index f5d4fd2c2..8ace45a89 100644 --- a/packages/taler-harness/src/index.ts +++ b/packages/taler-harness/src/index.ts @@ -20,7 +20,7 @@ import { addPaytoQueryParams, Amounts, - BankAccessApiClient, + TalerCorebankApiClient, Configuration, decodeCrock, j2s, @@ -236,7 +236,7 @@ deploymentCli console.log(tipReserveResp); - const bankAccessApiClient = new BankAccessApiClient( + const bankAccessApiClient = new TalerCorebankApiClient( args.tipTopup.bankAccessUrl, { auth: { diff --git a/packages/taler-harness/src/integrationtests/test-age-restrictions-merchant.ts b/packages/taler-harness/src/integrationtests/test-age-restrictions-merchant.ts index 7f936a479..90b08724f 100644 --- a/packages/taler-harness/src/integrationtests/test-age-restrictions-merchant.ts +++ b/packages/taler-harness/src/integrationtests/test-age-restrictions-merchant.ts @@ -27,7 +27,7 @@ import { withdrawViaBankV2, } from "../harness/helpers.js"; import { - BankAccessApiClient, + TalerCorebankApiClient, MerchantApiClient, WireGatewayApiClient, } from "@gnu-taler/taler-util"; @@ -179,7 +179,7 @@ export async function runAgeRestrictionsMerchantTest(t: GlobalTestState) { // Pay with coin from tipping { - const bankClient = new BankAccessApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); const mbu = await bankClient.createRandomBankUser(); const tipReserveResp = await merchantClient.createTippingReserve({ exchange_url: exchange.baseUrl, diff --git a/packages/taler-harness/src/integrationtests/test-bank-api.ts b/packages/taler-harness/src/integrationtests/test-bank-api.ts index a13ff63c7..740e89c30 100644 --- a/packages/taler-harness/src/integrationtests/test-bank-api.ts +++ b/packages/taler-harness/src/integrationtests/test-bank-api.ts @@ -18,7 +18,7 @@ * Imports. */ import { - BankAccessApiClient, + TalerCorebankApiClient, CreditDebitIndicator, WireGatewayApiClient, createEddsaKeyPair, @@ -99,7 +99,7 @@ export async function runBankApiTest(t: GlobalTestState) { console.log("setup done!"); - const bankClient = new BankAccessApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); const bankUser = await bankClient.registerAccount("user1", "pw1"); diff --git a/packages/taler-harness/src/integrationtests/test-exchange-management.ts b/packages/taler-harness/src/integrationtests/test-exchange-management.ts index 9338a8988..329012e42 100644 --- a/packages/taler-harness/src/integrationtests/test-exchange-management.ts +++ b/packages/taler-harness/src/integrationtests/test-exchange-management.ts @@ -18,7 +18,7 @@ * Imports. */ import { - BankAccessApiClient, + TalerCorebankApiClient, ExchangesListResponse, TalerErrorCode, URL, @@ -263,7 +263,7 @@ export async function runExchangeManagementTest( // Create withdrawal operation - const bankClient = new BankAccessApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); const user = await bankClient.createRandomBankUser(); const wop = await bankClient.createWithdrawalOperation( diff --git a/packages/taler-harness/src/integrationtests/test-kyc.ts b/packages/taler-harness/src/integrationtests/test-kyc.ts index 1f7358b66..2b2b57183 100644 --- a/packages/taler-harness/src/integrationtests/test-kyc.ts +++ b/packages/taler-harness/src/integrationtests/test-kyc.ts @@ -18,7 +18,7 @@ * Imports. */ import { - BankAccessApiClient, + TalerCorebankApiClient, Duration, j2s, Logger, @@ -302,7 +302,7 @@ export async function runKycTest(t: GlobalTestState) { // Withdraw digital cash into the wallet. - const bankClient = new BankAccessApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); const amount = "TESTKUDOS:20"; const user = await bankClient.createRandomBankUser(); diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-api-bankaccount.ts b/packages/taler-harness/src/integrationtests/test-libeufin-api-bankaccount.ts deleted file mode 100644 index e5e3dfe64..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-api-bankaccount.ts +++ /dev/null @@ -1,108 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { - LibeufinNexusApi, - LibeufinNexusService, - LibeufinSandboxService, - LibeufinSandboxApi, - findNexusPayment, -} from "../harness/libeufin.js"; - -/** - * Run basic test with LibEuFin. - */ -export async function runLibeufinApiBankaccountTest(t: GlobalTestState) { - const nexus = await LibeufinNexusService.create(t, { - httpPort: 5011, - databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-nexus.sqlite3`, - }); - await nexus.start(); - await nexus.pingUntilAvailable(); - - await LibeufinNexusApi.createUser(nexus, { - username: "one", - password: "testing-the-bankaccount-api", - }); - const sandbox = await LibeufinSandboxService.create(t, { - httpPort: 5012, - databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-sandbox.sqlite3`, - }); - await sandbox.start(); - await sandbox.pingUntilAvailable(); - await LibeufinSandboxApi.createEbicsHost(sandbox, "mock"); - await LibeufinSandboxApi.createDemobankAccount( - "mock", - "password-unused", - { baseUrl: sandbox.baseUrl + "/demobanks/default/access-api/" }, - "DE71500105179674997361", - ); - await LibeufinSandboxApi.createDemobankEbicsSubscriber( - { - hostID: "mock", - partnerID: "mock", - userID: "mock", - }, - "mock", - { baseUrl: sandbox.baseUrl + "/demobanks/default/" }, - ); - await LibeufinNexusApi.createEbicsBankConnection(nexus, { - name: "bankaccount-api-test-connection", - ebicsURL: "http://localhost:5012/ebicsweb", - hostID: "mock", - userID: "mock", - partnerID: "mock", - }); - await LibeufinNexusApi.connectBankConnection( - nexus, - "bankaccount-api-test-connection", - ); - await LibeufinNexusApi.fetchAccounts( - nexus, - "bankaccount-api-test-connection", - ); - - await LibeufinNexusApi.importConnectionAccount( - nexus, - "bankaccount-api-test-connection", - "mock", - "local-mock", - ); - await LibeufinSandboxApi.simulateIncomingTransaction( - sandbox, - "mock", // creditor bankaccount label - { - debtorIban: "DE84500105176881385584", - debtorBic: "BELADEBEXXX", - debtorName: "mock2", - amount: "EUR:1", - subject: "mock subject", - }, - ); - await LibeufinNexusApi.fetchTransactions(nexus, "local-mock"); - let transactions = await LibeufinNexusApi.getAccountTransactions( - nexus, - "local-mock", - ); - let el = findNexusPayment("mock subject", transactions); - t.assertTrue(el instanceof Object); -} - -runLibeufinApiBankaccountTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-api-bankconnection.ts b/packages/taler-harness/src/integrationtests/test-libeufin-api-bankconnection.ts deleted file mode 100644 index 243500dc9..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-api-bankconnection.ts +++ /dev/null @@ -1,56 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { LibeufinNexusApi, LibeufinNexusService } from "../harness/libeufin.js"; - -/** - * Run basic test with LibEuFin. - */ -export async function runLibeufinApiBankconnectionTest(t: GlobalTestState) { - const nexus = await LibeufinNexusService.create(t, { - httpPort: 5011, - databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-nexus.sqlite3`, - }); - await nexus.start(); - await nexus.pingUntilAvailable(); - - await LibeufinNexusApi.createUser(nexus, { - username: "one", - password: "testing-the-bankconnection-api", - }); - - await LibeufinNexusApi.createEbicsBankConnection(nexus, { - name: "bankconnection-api-test-connection", - ebicsURL: "http://localhost:5012/ebicsweb", - hostID: "mock", - userID: "mock", - partnerID: "mock", - }); - - let connections = await LibeufinNexusApi.getAllConnections(nexus); - t.assertTrue(connections.bankConnections.length == 1); - - await LibeufinNexusApi.deleteBankConnection(nexus, { - bankConnectionId: "bankconnection-api-test-connection", - }); - connections = await LibeufinNexusApi.getAllConnections(nexus); - t.assertTrue(connections.bankConnections.length == 0); -} -runLibeufinApiBankconnectionTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-api-facade-bad-request.ts b/packages/taler-harness/src/integrationtests/test-libeufin-api-facade-bad-request.ts deleted file mode 100644 index 27cc81588..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-api-facade-bad-request.ts +++ /dev/null @@ -1,68 +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 - */ - -/** - * Imports. - */ -import { URL } from "@gnu-taler/taler-util"; -import { GlobalTestState, harnessHttpLib } from "../harness/harness.js"; -import { - launchLibeufinServices, - NexusUserBundle, - SandboxUserBundle, -} from "../harness/libeufin.js"; -import { - createPlatformHttpLib, - makeBasicAuthHeader, -} from "@gnu-taler/taler-util/http"; - -export async function runLibeufinApiFacadeBadRequestTest(t: GlobalTestState) { - /** - * User saltetd "01" - */ - const user01nexus = new NexusUserBundle( - "01", - "http://localhost:5010/ebicsweb", - ); - const user01sandbox = new SandboxUserBundle("01"); - - /** - * Launch Sandbox and Nexus. - */ - const libeufinServices = await launchLibeufinServices( - t, - [user01nexus], - [user01sandbox], - ["twg"], - ); - console.log("malformed facade"); - const baseUrl = libeufinServices.libeufinNexus.baseUrl; - let url = new URL("facades", baseUrl); - let resp = await harnessHttpLib.fetch(url.href, { - method: "POST", - body: { - name: "malformed-facade", - type: "taler-wire-gateway", - config: {}, // malformation here. - }, - headers: { - Authorization: makeBasicAuthHeader("admin", "test"), - }, - }); - t.assertTrue(resp.status == 400); -} - -runLibeufinApiFacadeBadRequestTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-api-facade.ts b/packages/taler-harness/src/integrationtests/test-libeufin-api-facade.ts deleted file mode 100644 index a819dd481..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-api-facade.ts +++ /dev/null @@ -1,70 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { - SandboxUserBundle, - NexusUserBundle, - launchLibeufinServices, - LibeufinNexusApi, -} from "../harness/libeufin.js"; - -/** - * Run basic test with LibEuFin. - */ -export async function runLibeufinApiFacadeTest(t: GlobalTestState) { - /** - * User saltetd "01" - */ - const user01nexus = new NexusUserBundle( - "01", - "http://localhost:5010/ebicsweb", - ); - const user01sandbox = new SandboxUserBundle("01"); - - /** - * Launch Sandbox and Nexus. - */ - const libeufinServices = await launchLibeufinServices( - t, - [user01nexus], - [user01sandbox], - ["twg"], - ); - let resp = await LibeufinNexusApi.getAllFacades( - libeufinServices.libeufinNexus, - ); - // check that original facade shows up. - t.assertTrue(resp.facades[0].name == user01nexus.twgReq["name"]); - - const twgBaseUrl: string = resp.facades[0]["baseUrl"]; - t.assertTrue(typeof twgBaseUrl === "string"); - t.assertTrue(twgBaseUrl.startsWith("http://")); - t.assertTrue(twgBaseUrl.endsWith("/")); - - // delete it. - await LibeufinNexusApi.deleteFacade( - libeufinServices.libeufinNexus, - user01nexus.twgReq["name"], - ); - resp = await LibeufinNexusApi.getAllFacades(libeufinServices.libeufinNexus); - t.assertTrue(!resp.hasOwnProperty("facades")); -} - -runLibeufinApiFacadeTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-api-permissions.ts b/packages/taler-harness/src/integrationtests/test-libeufin-api-permissions.ts deleted file mode 100644 index 56443c20a..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-api-permissions.ts +++ /dev/null @@ -1,65 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { - NexusUserBundle, - LibeufinNexusApi, - LibeufinNexusService, -} from "../harness/libeufin.js"; - -/** - * Run basic test with LibEuFin. - */ -export async function runLibeufinApiPermissionsTest(t: GlobalTestState) { - const nexus = await LibeufinNexusService.create(t, { - httpPort: 5011, - databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-nexus.sqlite3`, - }); - await nexus.start(); - await nexus.pingUntilAvailable(); - - const user01nexus = new NexusUserBundle( - "01", - "http://localhost:5010/ebicsweb", - ); - - await LibeufinNexusApi.createUser(nexus, user01nexus.userReq); - await LibeufinNexusApi.postPermission( - nexus, - user01nexus.twgTransferPermission, - ); - let transferPermission = await LibeufinNexusApi.getAllPermissions(nexus); - let element = transferPermission["permissions"].pop(); - t.assertTrue(!!element); - t.assertTrue( - element["permissionName"] == "facade.talerwiregateway.transfer" && - element["subjectId"] == "username-01", - ); - let denyTransfer = user01nexus.twgTransferPermission; - - // Now revoke permission. - denyTransfer["action"] = "revoke"; - await LibeufinNexusApi.postPermission(nexus, denyTransfer); - - transferPermission = await LibeufinNexusApi.getAllPermissions(nexus); - t.assertTrue(transferPermission["permissions"].length == 0); -} - -runLibeufinApiPermissionsTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-api-sandbox-camt.ts b/packages/taler-harness/src/integrationtests/test-libeufin-api-sandbox-camt.ts deleted file mode 100644 index 22b411dc2..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-api-sandbox-camt.ts +++ /dev/null @@ -1,76 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { - LibeufinSandboxApi, - LibeufinSandboxService, -} from "../harness/libeufin.js"; - -// This test only checks that LibEuFin doesn't fail when -// it generates Camt statements - no assertions take place. -// Furthermore, it prints the Camt.053 being generated. -export async function runLibeufinApiSandboxCamtTest(t: GlobalTestState) { - const sandbox = await LibeufinSandboxService.create(t, { - httpPort: 5012, - databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-sandbox.sqlite3`, - }); - await sandbox.start(); - await sandbox.pingUntilAvailable(); - - await LibeufinSandboxApi.createDemobankAccount( - "mock-account-0", - "password-unused", - { baseUrl: sandbox.baseUrl + "/demobanks/default/access-api/" }, - ); - await LibeufinSandboxApi.createDemobankAccount( - "mock-account-1", - "password-unused", - { baseUrl: sandbox.baseUrl + "/demobanks/default/access-api/" }, - ); - await sandbox.makeTransaction( - "mock-account-0", - "mock-account-1", - "EUR:1", - "+1", - ); - await sandbox.makeTransaction( - "mock-account-0", - "mock-account-1", - "EUR:1", - "+1", - ); - await sandbox.makeTransaction( - "mock-account-0", - "mock-account-1", - "EUR:1", - "+1", - ); - await sandbox.makeTransaction( - "mock-account-1", - "mock-account-0", - "EUR:5", - "minus 5", - ); - await sandbox.c53tick(); - let ret = await LibeufinSandboxApi.getCamt053(sandbox, "mock-account-1"); - console.log(ret); -} -runLibeufinApiSandboxCamtTest.experimental = true; -runLibeufinApiSandboxCamtTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-api-sandbox-transactions.ts b/packages/taler-harness/src/integrationtests/test-libeufin-api-sandbox-transactions.ts deleted file mode 100644 index 6cfc55aa6..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-api-sandbox-transactions.ts +++ /dev/null @@ -1,69 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { - LibeufinSandboxApi, - LibeufinSandboxService, -} from "../harness/libeufin.js"; - -export async function runLibeufinApiSandboxTransactionsTest( - t: GlobalTestState, -) { - const sandbox = await LibeufinSandboxService.create(t, { - httpPort: 5012, - databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-sandbox.sqlite3`, - }); - await sandbox.start(); - await sandbox.pingUntilAvailable(); - await LibeufinSandboxApi.createDemobankAccount( - "mock-account", - "password-unused", - { baseUrl: sandbox.baseUrl + "/demobanks/default/access-api/" }, - "DE71500105179674997361", - ); - await LibeufinSandboxApi.simulateIncomingTransaction( - sandbox, - "mock-account", - { - debtorIban: "DE84500105176881385584", - debtorBic: "BELADEBEXXX", - debtorName: "mock2", - subject: "mock subject", - amount: "EUR:1", - }, - ); - await LibeufinSandboxApi.simulateIncomingTransaction( - sandbox, - "mock-account", - { - debtorIban: "DE84500105176881385584", - debtorBic: "BELADEBEXXX", - debtorName: "mock2", - subject: "mock subject 2", - amount: "EUR:1.1", - }, - ); - let ret = await LibeufinSandboxApi.getAccountInfoWithBalance( - sandbox, - "mock-account", - ); - t.assertAmountEquals(ret.balance, "EUR:2.1"); -} -runLibeufinApiSandboxTransactionsTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-api-scheduling.ts b/packages/taler-harness/src/integrationtests/test-libeufin-api-scheduling.ts deleted file mode 100644 index 15ed2ab78..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-api-scheduling.ts +++ /dev/null @@ -1,106 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { - launchLibeufinServices, - LibeufinNexusApi, - LibeufinNexusService, - NexusUserBundle, - SandboxUserBundle, -} from "../harness/libeufin.js"; - -/** - * Test Nexus scheduling API. It creates a task, check whether it shows - * up, then deletes it, and check if it's gone. Ideally, a check over the - * _liveliness_ of a scheduled task should happen. - */ -export async function runLibeufinApiSchedulingTest(t: GlobalTestState) { - const nexus = await LibeufinNexusService.create(t, { - httpPort: 5011, - databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-nexus.sqlite3`, - }); - await nexus.start(); - await nexus.pingUntilAvailable(); - - const user01nexus = new NexusUserBundle( - "01", - "http://localhost:5010/ebicsweb", - ); - const user01sandbox = new SandboxUserBundle("01"); - await launchLibeufinServices(t, [user01nexus], [user01sandbox]); - await LibeufinNexusApi.postTask(nexus, user01nexus.localAccountName, { - name: "test-task", - cronspec: "* * *", - type: "fetch", - params: { - level: "all", - rangeType: "all", - }, - }); - let resp = await LibeufinNexusApi.getTask( - nexus, - user01nexus.localAccountName, - "test-task", - ); - t.assertTrue(resp.taskName == "test-task"); - await LibeufinNexusApi.deleteTask( - nexus, - user01nexus.localAccountName, - "test-task", - ); - try { - await LibeufinNexusApi.getTask( - nexus, - user01nexus.localAccountName, - "test-task", - ); - } catch (err: any) { - t.assertTrue(err.response.status == 404); - } - - // Same with submit task. - await LibeufinNexusApi.postTask(nexus, user01nexus.localAccountName, { - name: "test-task", - cronspec: "* * *", - type: "submit", - params: {}, - }); - resp = await LibeufinNexusApi.getTask( - nexus, - user01nexus.localAccountName, - "test-task", - ); - t.assertTrue(resp.taskName == "test-task"); - await LibeufinNexusApi.deleteTask( - nexus, - user01nexus.localAccountName, - "test-task", - ); - try { - await LibeufinNexusApi.getTask( - nexus, - user01nexus.localAccountName, - "test-task", - ); - } catch (err: any) { - t.assertTrue(err.response.status == 404); - } -} -runLibeufinApiSchedulingTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-api-users.ts b/packages/taler-harness/src/integrationtests/test-libeufin-api-users.ts deleted file mode 100644 index 662b22bbe..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-api-users.ts +++ /dev/null @@ -1,63 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { LibeufinNexusApi, LibeufinNexusService } from "../harness/libeufin.js"; - -/** - * Run basic test with LibEuFin. - */ -export async function runLibeufinApiUsersTest(t: GlobalTestState) { - const nexus = await LibeufinNexusService.create(t, { - httpPort: 5011, - databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-nexus.sqlite3`, - }); - await nexus.start(); - await nexus.pingUntilAvailable(); - - await LibeufinNexusApi.createUser(nexus, { - username: "one", - password: "will-be-changed", - }); - - await LibeufinNexusApi.changePassword( - nexus, - "one", - { - newPassword: "got-changed", - }, - { - auth: { - username: "admin", - password: "test", - }, - }, - ); - - let resp = await LibeufinNexusApi.getUser(nexus, { - auth: { - username: "one", - password: "got-changed", - }, - }); - console.log(resp); - t.assertTrue(resp["username"] == "one" && !resp["superuser"]); -} - -runLibeufinApiUsersTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-bad-gateway.ts b/packages/taler-harness/src/integrationtests/test-libeufin-bad-gateway.ts deleted file mode 100644 index 1187d923b..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-bad-gateway.ts +++ /dev/null @@ -1,75 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState, delayMs } from "../harness/harness.js"; -import { - NexusUserBundle, - LibeufinNexusApi, - LibeufinNexusService, - LibeufinSandboxService, -} from "../harness/libeufin.js"; - -/** - * Testing how Nexus reacts when the Sandbox is unreachable. - * Typically, because the user specified a wrong EBICS endpoint. - */ -export async function runLibeufinBadGatewayTest(t: GlobalTestState) { - /** - * User saltetd "01" - */ - const user01nexus = new NexusUserBundle( - "01", - "http://localhost:5010/not-found", // the EBICS endpoint at Sandbox - ); - - // Start Nexus - const libeufinNexus = await LibeufinNexusService.create(t, { - httpPort: 5011, - databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-nexus.sqlite3`, - }); - await libeufinNexus.start(); - await libeufinNexus.pingUntilAvailable(); - - // Start Sandbox - const libeufinSandbox = await LibeufinSandboxService.create(t, { - httpPort: 5010, - databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-sandbox.sqlite3`, - }); - await libeufinSandbox.start(); - await libeufinSandbox.pingUntilAvailable(); - - // Connecting to a non-existent Sandbox endpoint. - await LibeufinNexusApi.createEbicsBankConnection( - libeufinNexus, - user01nexus.connReq, - ); - - // 502 Bad Gateway expected. - try { - await LibeufinNexusApi.connectBankConnection( - libeufinNexus, - user01nexus.connReq.name, - ); - } catch (e: any) { - t.assertTrue(e.response.status == 502); - return; - } - t.assertTrue(false); -} -runLibeufinBadGatewayTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-basic.ts b/packages/taler-harness/src/integrationtests/test-libeufin-basic.ts deleted file mode 100644 index d87278197..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-basic.ts +++ /dev/null @@ -1,317 +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 - */ - -/** - * Imports. - */ -import { - AbsoluteTime, - Duration, - MerchantContractTerms, -} from "@gnu-taler/taler-util"; -import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js"; -import { - DbInfo, - ExchangeService, - GlobalTestState, - HarnessExchangeBankAccount, - MerchantService, - WalletClient, - setupDb, -} from "../harness/harness.js"; -import { - createWalletDaemonWithClient, - makeTestPaymentV2, -} from "../harness/helpers.js"; -import { - LibeufinNexusApi, - LibeufinNexusService, - LibeufinSandboxApi, - LibeufinSandboxService, -} from "../harness/libeufin.js"; - -const exchangeIban = "DE71500105179674997361"; -const customerIban = "DE84500105176881385584"; -const customerBic = "BELADEBEXXX"; -const merchantIban = "DE42500105171245624648"; - -export interface LibeufinTestEnvironment { - commonDb: DbInfo; - exchange: ExchangeService; - exchangeBankAccount: HarnessExchangeBankAccount; - merchant: MerchantService; - walletClient: WalletClient; - libeufinSandbox: LibeufinSandboxService; - libeufinNexus: LibeufinNexusService; -} - -/** - * Create a Taler environment with LibEuFin and an EBICS account. - */ -export async function createLibeufinTestEnvironment( - t: GlobalTestState, - coinConfig: CoinConfig[] = defaultCoinConfig.map((x) => x("EUR")), -): Promise { - const db = await setupDb(t); - - const libeufinSandbox = await LibeufinSandboxService.create(t, { - httpPort: 5010, - databaseJdbcUri: db.connStr, - }); - - await libeufinSandbox.start(); - await libeufinSandbox.pingUntilAvailable(); - - const libeufinNexus = await LibeufinNexusService.create(t, { - httpPort: 5011, - databaseJdbcUri: db.connStr, - }); - - await libeufinNexus.start(); - await libeufinNexus.pingUntilAvailable(); - - await LibeufinSandboxApi.createEbicsHost(libeufinSandbox, "host01"); - // Subscriber and bank Account for the exchange - await LibeufinSandboxApi.createDemobankAccount( - "exchangeacct", - "password-unused", - { baseUrl: libeufinSandbox.baseUrl + "/demobanks/default/access-api/" }, - exchangeIban, - ); - await LibeufinSandboxApi.createDemobankEbicsSubscriber( - { - hostID: "host01", - partnerID: "partner01", - userID: "user01", - }, - "exchangeacct", - { baseUrl: libeufinSandbox.baseUrl + "/demobanks/default/" }, - ); - - await LibeufinSandboxApi.createDemobankAccount( - "merchantacct", - "password-unused", - { baseUrl: libeufinSandbox.baseUrl + "/demobanks/default/access-api/" }, - merchantIban, - ); - await LibeufinSandboxApi.createDemobankEbicsSubscriber( - { - hostID: "host01", - partnerID: "partner02", - userID: "user02", - }, - "merchantacct", - { baseUrl: libeufinSandbox.baseUrl + "/demobanks/default/" }, - ); - - await LibeufinNexusApi.createEbicsBankConnection(libeufinNexus, { - name: "myconn", - ebicsURL: "http://localhost:5010/ebicsweb", - hostID: "host01", - partnerID: "partner01", - userID: "user01", - }); - await LibeufinNexusApi.connectBankConnection(libeufinNexus, "myconn"); - await LibeufinNexusApi.fetchAccounts(libeufinNexus, "myconn"); - await LibeufinNexusApi.importConnectionAccount( - libeufinNexus, - "myconn", - "exchangeacct", - "myacct", - ); - - await LibeufinNexusApi.createTwgFacade(libeufinNexus, { - name: "twg1", - accountName: "myacct", - connectionName: "myconn", - currency: "EUR", - reserveTransferLevel: "report", - }); - - await LibeufinNexusApi.createUser(libeufinNexus, { - username: "twguser", - password: "twgpw", - }); - - await LibeufinNexusApi.postPermission(libeufinNexus, { - action: "grant", - permission: { - subjectType: "user", - subjectId: "twguser", - resourceType: "facade", - resourceId: "twg1", - permissionName: "facade.talerWireGateway.history", - }, - }); - - await LibeufinNexusApi.postPermission(libeufinNexus, { - action: "grant", - permission: { - subjectType: "user", - subjectId: "twguser", - resourceType: "facade", - resourceId: "twg1", - permissionName: "facade.talerWireGateway.transfer", - }, - }); - - const exchange = ExchangeService.create(t, { - name: "testexchange-1", - currency: "EUR", - httpPort: 8081, - database: db.connStr, - }); - - const merchant = await MerchantService.create(t, { - name: "testmerchant-1", - currency: "EUR", - httpPort: 8083, - database: db.connStr, - }); - - const exchangeBankAccount: HarnessExchangeBankAccount = { - accountName: "twguser", - accountPassword: "twgpw", - accountPaytoUri: `payto://iban/${exchangeIban}?receiver-name=Exchange`, - wireGatewayApiBaseUrl: - "http://localhost:5011/facades/twg1/taler-wire-gateway/", - }; - - exchange.addBankAccount("1", exchangeBankAccount); - - exchange.addCoinConfigList(coinConfig); - - await exchange.start(); - await exchange.pingUntilAvailable(); - - merchant.addExchange(exchange); - - await merchant.start(); - await merchant.pingUntilAvailable(); - - await merchant.addInstanceWithWireAccount({ - id: "default", - name: "Default Instance", - paytoUris: [`payto://iban/${merchantIban}?receiver-name=Merchant`], - defaultWireTransferDelay: Duration.toTalerProtocolDuration( - Duration.getZero(), - ), - }); - - console.log("setup done!"); - - const { walletClient } = await createWalletDaemonWithClient(t, { - name: "default", - }); - - return { - commonDb: db, - exchange, - merchant, - walletClient, - exchangeBankAccount, - libeufinNexus, - libeufinSandbox, - }; -} - -/** - * Run basic test with LibEuFin. - */ -export async function runLibeufinBasicTest(t: GlobalTestState) { - // Set up test environment - - const { walletClient, exchange, merchant, libeufinSandbox, libeufinNexus } = - await createLibeufinTestEnvironment(t); - - await walletClient.call(WalletApiOperation.AddExchange, { - exchangeBaseUrl: exchange.baseUrl, - }); - - const wr = await walletClient.call( - WalletApiOperation.AcceptManualWithdrawal, - { - exchangeBaseUrl: exchange.baseUrl, - amount: "EUR:15", - }, - ); - - const reservePub: string = wr.reservePub; - - await LibeufinSandboxApi.simulateIncomingTransaction( - libeufinSandbox, - "exchangeacct", - { - amount: "EUR:15.00", - debtorBic: customerBic, - debtorIban: customerIban, - debtorName: "Jane Customer", - subject: `Taler Top-up ${reservePub}`, - }, - ); - - await LibeufinNexusApi.fetchTransactions(libeufinNexus, "myacct"); - - await exchange.runWirewatchOnce(); - - await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); - - const bal = await walletClient.call(WalletApiOperation.GetBalances, {}); - console.log("balances", JSON.stringify(bal, undefined, 2)); - t.assertAmountEquals(bal.balances[0].available, "EUR:14.7"); - - const order: Partial = { - summary: "Buy me!", - amount: "EUR:5", - fulfillment_url: "taler://fulfillment-success/thx", - wire_transfer_deadline: AbsoluteTime.toProtocolTimestamp( - AbsoluteTime.now(), - ), - }; - - await makeTestPaymentV2(t, { walletClient, merchant, order }); - - await exchange.runAggregatorOnce(); - await exchange.runTransferOnce(); - - await LibeufinNexusApi.submitAllPaymentInitiations(libeufinNexus, "myacct"); - - const exchangeTransactions = await LibeufinSandboxApi.getAccountTransactions( - libeufinSandbox, - "exchangeacct", - ); - - console.log( - "exchange transactions:", - JSON.stringify(exchangeTransactions, undefined, 2), - ); - - t.assertDeepEqual( - exchangeTransactions.payments[0].creditDebitIndicator, - "credit", - ); - t.assertDeepEqual( - exchangeTransactions.payments[1].creditDebitIndicator, - "debit", - ); - t.assertDeepEqual(exchangeTransactions.payments[1].debtorIban, exchangeIban); - t.assertDeepEqual( - exchangeTransactions.payments[1].creditorIban, - merchantIban, - ); -} -runLibeufinBasicTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-c5x.ts b/packages/taler-harness/src/integrationtests/test-libeufin-c5x.ts deleted file mode 100644 index 5097bc4d3..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-c5x.ts +++ /dev/null @@ -1,147 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { - launchLibeufinServices, - LibeufinNexusApi, - NexusUserBundle, - SandboxUserBundle, -} from "../harness/libeufin.js"; - -/** - * This test checks how the C52 and C53 coordinate. It'll test - * whether fresh transactions stop showing as C52 after they get - * included in a bank statement. - */ -export async function runLibeufinC5xTest(t: GlobalTestState) { - /** - * User saltetd "01" - */ - const user01nexus = new NexusUserBundle( - "01", - "http://localhost:5010/ebicsweb", - ); - const user01sandbox = new SandboxUserBundle("01"); - - /** - * User saltetd "02". - */ - const user02nexus = new NexusUserBundle( - "02", - "http://localhost:5010/ebicsweb", - ); - const user02sandbox = new SandboxUserBundle("02"); - - /** - * Launch Sandbox and Nexus. - */ - const libeufinServices = await launchLibeufinServices( - t, - [user01nexus, user02nexus], - [user01sandbox, user02sandbox], - ["twg"], - ); - - // Check that C52 and C53 have zero entries. - - // C52 - await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - "all", // range - "report", // level - ); - // C53 - await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - "all", // range - "statement", // level - ); - const nexusTxs = await LibeufinNexusApi.getAccountTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - ); - t.assertTrue(nexusTxs["transactions"].length == 0); - - // Addressing one payment to user 01 - await libeufinServices.libeufinSandbox.makeTransaction( - user02sandbox.ebicsBankAccount.label, // debit - user01sandbox.ebicsBankAccount.label, // credit - "EUR:10", - "first payment", - ); - - let expectOne = await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - "all", // range - "report", // C52 - ); - t.assertTrue(expectOne.newTransactions == 1); - t.assertTrue(expectOne.downloadedTransactions == 1); - - /* Expect zero payments being downloaded because the - * previous request consumed already the one pending - * payment. - */ - let expectZero = await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - "all", // range - "report", // C52 - ); - t.assertTrue(expectZero.newTransactions == 0); - t.assertTrue(expectZero.downloadedTransactions == 0); - - /** - * A statement should still account zero payments because - * so far the payment made before is still pending. - */ - expectZero = await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - "all", // range - "statement", // C53 - ); - t.assertTrue(expectZero.newTransactions == 0); - t.assertTrue(expectZero.downloadedTransactions == 0); - - /** - * Ticking now. That books any pending transaction. - */ - await libeufinServices.libeufinSandbox.c53tick(); - - /** - * A statement is now expected to download the transaction, - * although that got already ingested along the report - * earlier. Thus the transaction counts as downloaded but - * not as new. - */ - expectOne = await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - "all", // range - "statement", // C53 - ); - t.assertTrue(expectOne.downloadedTransactions == 1); - t.assertTrue(expectOne.newTransactions == 0); -} -runLibeufinC5xTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-facade-anastasis.ts b/packages/taler-harness/src/integrationtests/test-libeufin-facade-anastasis.ts deleted file mode 100644 index 0efd55f44..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-facade-anastasis.ts +++ /dev/null @@ -1,179 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { - SandboxUserBundle, - NexusUserBundle, - launchLibeufinServices, - LibeufinNexusApi, - LibeufinSandboxApi, -} from "../harness/libeufin.js"; - -/** - * Testing the Anastasis API, offered by the Anastasis facade. - */ -export async function runLibeufinAnastasisFacadeTest(t: GlobalTestState) { - /** - * User saltetd "01" - */ - const user01nexus = new NexusUserBundle( - "01", - "http://localhost:5010/ebicsweb", - ); - const user01sandbox = new SandboxUserBundle("01"); - - /** - * Launch Sandbox and Nexus. - */ - const libeufinServices = await launchLibeufinServices( - t, - [user01nexus], - [user01sandbox], - ["anastasis"], // create only one Anastasis facade. - ); - let resp = await LibeufinNexusApi.getAllFacades( - libeufinServices.libeufinNexus, - ); - // check that original facade shows up. - t.assertTrue( - resp["facades"][0]["name"] == user01nexus.anastasisReq["name"], - ); -const anastasisBaseUrl: string = resp["facades"][0]["baseUrl"]; - t.assertTrue(typeof anastasisBaseUrl === "string"); - t.assertTrue(anastasisBaseUrl.startsWith("http://")); - t.assertTrue(anastasisBaseUrl.endsWith("/")); - - await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - ); - - await LibeufinNexusApi.postPermission(libeufinServices.libeufinNexus, { - action: "grant", - permission: { - subjectId: user01nexus.userReq.username, - subjectType: "user", - resourceType: "facade", - resourceId: user01nexus.anastasisReq.name, - permissionName: "facade.anastasis.history", - }, - }); - - // check if empty. - let txsEmpty = await LibeufinNexusApi.getAnastasisTransactions( - libeufinServices.libeufinNexus, - anastasisBaseUrl, - { delta: 5 }, - ); - - t.assertTrue(txsEmpty.data.incoming_transactions.length == 0); - - LibeufinSandboxApi.simulateIncomingTransaction( - libeufinServices.libeufinSandbox, - user01sandbox.ebicsBankAccount.label, - { - debtorIban: "ES3314655813489414469157", - debtorBic: "BCMAESM1XXX", - debtorName: "Mock Donor", - subject: "Anastasis donation", - amount: "EUR:3", // Sandbox takes currency from its 'config' - }, - ); - - LibeufinSandboxApi.simulateIncomingTransaction( - libeufinServices.libeufinSandbox, - user01sandbox.ebicsBankAccount.label, - { - debtorIban: "ES3314655813489414469157", - debtorBic: "BCMAESM1XXX", - debtorName: "Mock Donor", - subject: "another Anastasis donation", - amount: "EUR:1", // Sandbox takes currency from its "config" - }, - ); - - await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - ); - - let txs = await LibeufinNexusApi.getAnastasisTransactions( - libeufinServices.libeufinNexus, - anastasisBaseUrl, - { delta: 5 }, - user01nexus.userReq.username, - user01nexus.userReq.password, - ); - - // check the two payments show up - let txsList = txs.data.incoming_transactions; - t.assertTrue(txsList.length == 2); - t.assertTrue( - [txsList[0].subject, txsList[1].subject].includes("Anastasis donation"), - ); - t.assertTrue( - [txsList[0].subject, txsList[1].subject].includes( - "another Anastasis donation", - ), - ); - t.assertTrue(txsList[0].row_id == 1); - t.assertTrue(txsList[1].row_id == 2); - - LibeufinSandboxApi.simulateIncomingTransaction( - libeufinServices.libeufinSandbox, - user01sandbox.ebicsBankAccount.label, - { - debtorIban: "ES3314655813489414469157", - debtorBic: "BCMAESM1XXX", - debtorName: "Mock Donor", - subject: "last Anastasis donation", - amount: "EUR:10.10", // Sandbox takes currency from its "config" - }, - ); - - await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - ); - - let txsLast = await LibeufinNexusApi.getAnastasisTransactions( - libeufinServices.libeufinNexus, - anastasisBaseUrl, - { delta: 5, start: 2 }, - user01nexus.userReq.username, - user01nexus.userReq.password, - ); - console.log( - txsLast.data.incoming_transactions[0].subject == "last Anastasis donation", - ); - - let txsReverse = await LibeufinNexusApi.getAnastasisTransactions( - libeufinServices.libeufinNexus, - anastasisBaseUrl, - { delta: -5, start: 4 }, - user01nexus.userReq.username, - user01nexus.userReq.password, - ); - t.assertTrue(txsReverse.data.incoming_transactions[0].row_id == 3); - t.assertTrue(txsReverse.data.incoming_transactions[1].row_id == 2); - t.assertTrue(txsReverse.data.incoming_transactions[2].row_id == 1); -} - -runLibeufinAnastasisFacadeTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-keyrotation.ts b/packages/taler-harness/src/integrationtests/test-libeufin-keyrotation.ts deleted file mode 100644 index a2c21d5d8..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-keyrotation.ts +++ /dev/null @@ -1,82 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { - SandboxUserBundle, - NexusUserBundle, - launchLibeufinServices, - LibeufinSandboxApi, - LibeufinNexusApi, -} from "../harness/libeufin.js"; - -/** - * Run basic test with LibEuFin. - */ -export async function runLibeufinKeyrotationTest(t: GlobalTestState) { - /** - * User saltetd "01" - */ - const user01nexus = new NexusUserBundle( - "01", - "http://localhost:5010/ebicsweb", - ); - const user01sandbox = new SandboxUserBundle("01"); - - /** - * Launch Sandbox and Nexus. - */ - const libeufinServices = await launchLibeufinServices( - t, - [user01nexus], - [user01sandbox], - ); - - await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - ); - - /* Rotate the Sandbox keys, and fetch the transactions again */ - await LibeufinSandboxApi.rotateKeys( - libeufinServices.libeufinSandbox, - user01sandbox.ebicsBankAccount.subscriber.hostID, - ); - - try { - await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - ); - } catch (e: any) { - /** - * Asserting that Nexus responded with a 500 Internal server - * error, because the bank signed the last response with a new - * key pair that was never downloaded by Nexus. - * - * NOTE: the bank accepted the request addressed to the old - * public key. Should it in this case reject the request even - * before trying to verify it? - */ - t.assertTrue(e.response.status == 500); - // FIXME: uncomment and adapt the following command after #6723 is fixed. - // t.assertTrue(e.response.data.code == 9000); - } -} -runLibeufinKeyrotationTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-nexus-balance.ts b/packages/taler-harness/src/integrationtests/test-libeufin-nexus-balance.ts deleted file mode 100644 index 868f93759..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-nexus-balance.ts +++ /dev/null @@ -1,117 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { - SandboxUserBundle, - NexusUserBundle, - launchLibeufinServices, - LibeufinNexusApi, -} from "../harness/libeufin.js"; - -/** - * This test checks how the C52 and C53 coordinate. It'll test - * whether fresh transactions stop showing as C52 after they get - * included in a bank statement. - */ -export async function runLibeufinNexusBalanceTest(t: GlobalTestState) { - /** - * User saltetd "01" - */ - const user01nexus = new NexusUserBundle( - "01", - "http://localhost:5010/ebicsweb", - ); - const user01sandbox = new SandboxUserBundle("01"); - - /** - * User saltetd "02". - */ - const user02nexus = new NexusUserBundle( - "02", - "http://localhost:5010/ebicsweb", - ); - const user02sandbox = new SandboxUserBundle("02"); - - /** - * Launch Sandbox and Nexus. - */ - const libeufinServices = await launchLibeufinServices( - t, - [user01nexus, user02nexus], - [user01sandbox, user02sandbox], - ["twg"], - ); - - // user 01 gets 10 - await libeufinServices.libeufinSandbox.makeTransaction( - user02sandbox.ebicsBankAccount.label, // debit - user01sandbox.ebicsBankAccount.label, // credit - "EUR:10", - "first payment", - ); - // user 01 gets another 10 - await libeufinServices.libeufinSandbox.makeTransaction( - user02sandbox.ebicsBankAccount.label, // debit - user01sandbox.ebicsBankAccount.label, // credit - "EUR:10", - "second payment", - ); - - await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - "all", // range - "report", // level - ); - - // Check that user 01 has 20, via Nexus. - let accountInfo = await LibeufinNexusApi.getBankAccount( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - ); - t.assertAmountEquals(accountInfo.data.lastSeenBalance, "EUR:20"); - - // Booking the first two transactions. - await libeufinServices.libeufinSandbox.c53tick(); - - // user 01 gives 30 - await libeufinServices.libeufinSandbox.makeTransaction( - user01sandbox.ebicsBankAccount.label, - user02sandbox.ebicsBankAccount.label, - "EUR:30", - "third payment", - ); - - await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - "all", // range - "report", // level - ); - - let accountInfoDebit = await LibeufinNexusApi.getBankAccount( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - ); - t.assertDeepEqual(accountInfoDebit.data.lastSeenBalance, "-EUR:10"); -} - -runLibeufinNexusBalanceTest.suites = ["libeufin"]; -runLibeufinNexusBalanceTest.experimental = true; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-refund-multiple-users.ts b/packages/taler-harness/src/integrationtests/test-libeufin-refund-multiple-users.ts deleted file mode 100644 index 245f34331..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-refund-multiple-users.ts +++ /dev/null @@ -1,104 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState, delayMs } from "../harness/harness.js"; -import { - SandboxUserBundle, - NexusUserBundle, - launchLibeufinServices, - LibeufinSandboxApi, - LibeufinNexusApi, -} from "../harness/libeufin.js"; - -/** - * User 01 expects a refund from user 02, and expectedly user 03 - * should not be involved in the process. - */ -export async function runLibeufinRefundMultipleUsersTest(t: GlobalTestState) { - /** - * User saltetd "01" - */ - const user01nexus = new NexusUserBundle( - "01", - "http://localhost:5010/ebicsweb", - ); - const user01sandbox = new SandboxUserBundle("01"); - - /** - * User saltetd "02" - */ - const user02nexus = new NexusUserBundle( - "02", - "http://localhost:5010/ebicsweb", - ); - const user02sandbox = new SandboxUserBundle("02"); - - /** - * User saltetd "03" - */ - const user03nexus = new NexusUserBundle( - "03", - "http://localhost:5010/ebicsweb", - ); - const user03sandbox = new SandboxUserBundle("03"); - - /** - * Launch Sandbox and Nexus. - */ - const libeufinServices = await launchLibeufinServices( - t, - [user01nexus, user02nexus], - [user01sandbox, user02sandbox], - ["twg"], - ); - - // user 01 gets the payment - await libeufinServices.libeufinSandbox.makeTransaction( - user02sandbox.ebicsBankAccount.label, // debit - user01sandbox.ebicsBankAccount.label, // credit - "EUR:1", - "not a public key", - ); - - // user 01 fetches the payments - await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - ); - - // user 01 tries to submit the reimbursement, as - // the payment didn't have a valid public key in - // the subject. - await LibeufinNexusApi.submitInitiatedPayment( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - "1", // so far the only one that can exist. - ); - - // user 02 checks whether a reimbursement arrived. - let history = await LibeufinSandboxApi.getAccountTransactions( - libeufinServices.libeufinSandbox, - user02sandbox.ebicsBankAccount["label"], - ); - // reimbursement arrived IFF the total payments are 2: - // 1 the original (faulty) transaction + 1 the reimbursement. - t.assertTrue(history["payments"].length == 2); -} - -runLibeufinRefundMultipleUsersTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-refund.ts b/packages/taler-harness/src/integrationtests/test-libeufin-refund.ts deleted file mode 100644 index d37363bab..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-refund.ts +++ /dev/null @@ -1,101 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState, delayMs } from "../harness/harness.js"; -import { - SandboxUserBundle, - NexusUserBundle, - launchLibeufinServices, - LibeufinSandboxApi, - LibeufinNexusApi, -} from "../harness/libeufin.js"; - -/** - * Run basic test with LibEuFin. - */ -export async function runLibeufinRefundTest(t: GlobalTestState) { - /** - * User saltetd "01" - */ - const user01nexus = new NexusUserBundle( - "01", - "http://localhost:5010/ebicsweb", - ); - const user01sandbox = new SandboxUserBundle("01"); - - /** - * User saltetd "02" - */ - const user02nexus = new NexusUserBundle( - "02", - "http://localhost:5010/ebicsweb", - ); - const user02sandbox = new SandboxUserBundle("02"); - - /** - * Launch Sandbox and Nexus. - */ - const libeufinServices = await launchLibeufinServices( - t, - [user01nexus, user02nexus], - [user01sandbox, user02sandbox], - ["twg"], - ); - - // user 02 pays user 01 with a faulty (non Taler) subject. - await libeufinServices.libeufinSandbox.makeTransaction( - user02sandbox.ebicsBankAccount.label, // debit - user01sandbox.ebicsBankAccount.label, // credit - "EUR:1", - "not a public key", - ); - - // The bad payment should be now ingested and prepared as - // a reimbursement. - await LibeufinNexusApi.fetchTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - ); - // Check that the payment arrived at the Nexus. - const nexusTxs = await LibeufinNexusApi.getAccountTransactions( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - ); - t.assertTrue(nexusTxs["transactions"].length == 1); - - // Submit the reimbursement - await LibeufinNexusApi.submitInitiatedPayment( - libeufinServices.libeufinNexus, - user01nexus.localAccountName, - // The initiated payment (= the reimbursement) ID below - // got set by the Taler facade; at this point only one must - // exist. If "1" is not found, a 404 will make this test fail. - "1", - ); - - // user 02 checks whether the reimbursement arrived. - let history = await LibeufinSandboxApi.getAccountTransactions( - libeufinServices.libeufinSandbox, - user02sandbox.ebicsBankAccount["label"], - ); - // 2 payments must exist: 1 the original (faulty) payment + - // 1 the reimbursement. - t.assertTrue(history["payments"].length == 2); -} -runLibeufinRefundTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-sandbox-wire-transfer-cli.ts b/packages/taler-harness/src/integrationtests/test-libeufin-sandbox-wire-transfer-cli.ts deleted file mode 100644 index be467e2f1..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-sandbox-wire-transfer-cli.ts +++ /dev/null @@ -1,85 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { - LibeufinSandboxApi, - LibeufinSandboxService, -} from "../harness/libeufin.js"; - -export async function runLibeufinSandboxWireTransferCliTest( - t: GlobalTestState, -) { - const sandbox = await LibeufinSandboxService.create(t, { - httpPort: 5012, - databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-sandbox.sqlite3`, - }); - await sandbox.start(); - await sandbox.pingUntilAvailable(); - await LibeufinSandboxApi.createDemobankAccount( - "mock-account", - "password-unused", - { baseUrl: sandbox.baseUrl + "/demobanks/default/access-api/" }, - "DE71500105179674997361", - ); - await LibeufinSandboxApi.createDemobankAccount( - "mock-account-2", - "password-unused", - { baseUrl: sandbox.baseUrl + "/demobanks/default/access-api/" }, - "DE71500105179674997364", - ); - - await sandbox.makeTransaction( - "mock-account", - "mock-account-2", - "EUR:1", - "one!", - ); - await sandbox.makeTransaction( - "mock-account", - "mock-account-2", - "EUR:1", - "two!", - ); - await sandbox.makeTransaction( - "mock-account", - "mock-account-2", - "EUR:1", - "three!", - ); - await sandbox.makeTransaction( - "mock-account-2", - "mock-account", - "EUR:1", - "Give one back.", - ); - await sandbox.makeTransaction( - "mock-account-2", - "mock-account", - "EUR:0.11", - "Give fraction back.", - ); - let ret = await LibeufinSandboxApi.getAccountInfoWithBalance( - sandbox, - "mock-account-2", - ); - console.log(ret.balance); - t.assertTrue(ret.balance == "EUR:1.89"); -} -runLibeufinSandboxWireTransferCliTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-tutorial.ts b/packages/taler-harness/src/integrationtests/test-libeufin-tutorial.ts deleted file mode 100644 index 496b65ee3..000000000 --- a/packages/taler-harness/src/integrationtests/test-libeufin-tutorial.ts +++ /dev/null @@ -1,130 +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 - */ - -/** - * Imports. - */ -import { GlobalTestState } from "../harness/harness.js"; -import { - LibeufinNexusService, - LibeufinSandboxService, - LibeufinCli, -} from "../harness/libeufin.js"; - -/** - * Run basic test with LibEuFin. - */ -export async function runLibeufinTutorialTest(t: GlobalTestState) { - // Set up test environment - - 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`, - }); - - const nexusUser = { username: "foo", password: "secret" }; - const libeufinCli = new LibeufinCli(t, { - sandboxUrl: libeufinSandbox.baseUrl, - nexusUrl: libeufinNexus.baseUrl, - sandboxDatabaseUri: `jdbc:sqlite:${t.testDir}/libeufin-sandbox.sqlite3`, - nexusDatabaseUri: `jdbc:sqlite:${t.testDir}/libeufin-nexus.sqlite3`, - nexusUser: nexusUser, - }); - - const ebicsDetails = { - hostId: "testhost", - partnerId: "partner01", - userId: "user01", - }; - const bankAccountDetails = { - currency: "EUR", - iban: "DE18500105172929531888", - bic: "INGDDEFFXXX", - personName: "Jane Normal", - accountName: "testacct01", - }; - - await libeufinCli.checkSandbox(); - await libeufinCli.createEbicsHost("testhost"); - await libeufinCli.createEbicsSubscriber(ebicsDetails); - await libeufinCli.createEbicsBankAccount(ebicsDetails, bankAccountDetails); - await libeufinCli.generateTransactions(bankAccountDetails.accountName); - - await libeufinNexus.start(); - await libeufinNexus.pingUntilAvailable(); - - await libeufinNexus.createNexusSuperuser(nexusUser); - const connectionDetails = { - subscriberDetails: ebicsDetails, - ebicsUrl: `${libeufinSandbox.baseUrl}ebicsweb`, // FIXME: need appropriate URL concatenation - connectionName: "my-ebics-conn", - }; - await libeufinCli.createEbicsConnection(connectionDetails); - await libeufinCli.createBackupFile({ - passphrase: "secret", - outputFile: `${t.testDir}/connection-backup.json`, - connectionName: connectionDetails.connectionName, - }); - await libeufinCli.createKeyLetter({ - outputFile: `${t.testDir}/letter.pdf`, - connectionName: connectionDetails.connectionName, - }); - await libeufinCli.connect(connectionDetails.connectionName); - await libeufinCli.downloadBankAccounts(connectionDetails.connectionName); - await libeufinCli.listOfferedBankAccounts(connectionDetails.connectionName); - - const bankAccountImportDetails = { - offeredBankAccountName: bankAccountDetails.accountName, - nexusBankAccountName: "at-nexus-testacct01", - connectionName: connectionDetails.connectionName, - }; - - await libeufinCli.importBankAccount(bankAccountImportDetails); - await libeufinSandbox.c53tick(); - await libeufinCli.fetchTransactions( - bankAccountImportDetails.nexusBankAccountName, - ); - await libeufinCli.transactions(bankAccountImportDetails.nexusBankAccountName); - - const paymentDetails = { - creditorIban: "DE42500105171245624648", - creditorBic: "BELADEBEXXX", - creditorName: "Mina Musterfrau", - subject: "Purchase 01234", - amount: "1.0", - currency: "EUR", - nexusBankAccountName: bankAccountImportDetails.nexusBankAccountName, - }; - await libeufinCli.preparePayment(paymentDetails); - await libeufinCli.submitPayment(paymentDetails, "1"); - - await libeufinCli.newTalerWireGatewayFacade({ - accountName: bankAccountImportDetails.nexusBankAccountName, - connectionName: "my-ebics-conn", - currency: "EUR", - facadeName: "my-twg", - }); - await libeufinCli.listFacades(); -} -runLibeufinTutorialTest.suites = ["libeufin"]; diff --git a/packages/taler-harness/src/integrationtests/test-payment-fault.ts b/packages/taler-harness/src/integrationtests/test-payment-fault.ts index e57427fac..ca74a4ad6 100644 --- a/packages/taler-harness/src/integrationtests/test-payment-fault.ts +++ b/packages/taler-harness/src/integrationtests/test-payment-fault.ts @@ -22,7 +22,7 @@ * Imports. */ import { - BankAccessApiClient, + TalerCorebankApiClient, CoreApiResponse, MerchantApiClient, } from "@gnu-taler/taler-util"; @@ -127,7 +127,7 @@ export async function runPaymentFaultTest(t: GlobalTestState) { // Create withdrawal operation - const bankClient = new BankAccessApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); const user = await bankClient.createRandomBankUser(); const wop = await bankClient.createWithdrawalOperation( diff --git a/packages/taler-harness/src/integrationtests/test-tipping.ts b/packages/taler-harness/src/integrationtests/test-tipping.ts index 4140311ab..3d4ea6663 100644 --- a/packages/taler-harness/src/integrationtests/test-tipping.ts +++ b/packages/taler-harness/src/integrationtests/test-tipping.ts @@ -18,7 +18,7 @@ * Imports. */ import { - BankAccessApiClient, + TalerCorebankApiClient, MerchantApiClient, TransactionMajorState, WireGatewayApiClient, @@ -38,7 +38,7 @@ export async function runTippingTest(t: GlobalTestState) { const { walletClient, bank, exchange, merchant, exchangeBankAccount } = await createSimpleTestkudosEnvironmentV2(t); - const bankAccessApiClient = new BankAccessApiClient( + const bankAccessApiClient = new TalerCorebankApiClient( bank.bankAccessApiBaseUrl, ); const mbu = await bankAccessApiClient.createRandomBankUser(); diff --git a/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts b/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts index 9a0eb77ae..ae582fe60 100644 --- a/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts +++ b/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts @@ -18,7 +18,7 @@ * Imports. */ import { - BankAccessApiClient, + TalerCorebankApiClient, Duration, NotificationType, TransactionMajorState, @@ -121,7 +121,7 @@ export async function runWalletNotificationsTest(t: GlobalTestState) { skipDefaults: true, }); - const bankAccessApiClient = new BankAccessApiClient( + const bankAccessApiClient = new TalerCorebankApiClient( bank.bankAccessApiBaseUrl, ); const user = await bankAccessApiClient.createRandomBankUser(); diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-abort-bank.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-abort-bank.ts index aa5e2b770..4a0dd845b 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-abort-bank.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-abort-bank.ts @@ -17,7 +17,7 @@ /** * Imports. */ -import { BankAccessApiClient, TalerErrorCode } from "@gnu-taler/taler-util"; +import { TalerCorebankApiClient, TalerErrorCode } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { GlobalTestState } from "../harness/harness.js"; import { createSimpleTestkudosEnvironmentV2 } from "../harness/helpers.js"; @@ -33,7 +33,7 @@ export async function runWithdrawalAbortBankTest(t: GlobalTestState) { // Create a withdrawal operation - const bankAccessApiClient = new BankAccessApiClient( + const bankAccessApiClient = new TalerCorebankApiClient( bank.bankAccessApiBaseUrl, ); const user = await bankAccessApiClient.createRandomBankUser(); diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts index 232b6d7c2..4a2cc7df9 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts @@ -18,7 +18,7 @@ * Imports. */ import { - BankAccessApiClient, + TalerCorebankApiClient, j2s, NotificationType, TransactionMajorState, @@ -41,7 +41,7 @@ export async function runWithdrawalBankIntegratedTest(t: GlobalTestState) { // Create a withdrawal operation - const bankAccessApiClient = new BankAccessApiClient( + const bankAccessApiClient = new TalerCorebankApiClient( bank.bankAccessApiBaseUrl, ); const user = await bankAccessApiClient.createRandomBankUser(); diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-fakebank.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-fakebank.ts index ec6e54e6c..7cd0548a5 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-fakebank.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-fakebank.ts @@ -54,7 +54,10 @@ export async function runWithdrawalFakebankTest(t: GlobalTestState) { exchange.addBankAccount("1", { accountName: "exchange", accountPassword: "x", - wireGatewayApiBaseUrl: new URL("/exchange/", bank.baseUrl).href, + wireGatewayApiBaseUrl: new URL( + "/accounts/exchange/taler-wire-gateway", + bank.baseUrl, + ).href, accountPaytoUri: "payto://x-taler-bank/localhost/exchange", }); diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-fees.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-fees.ts index bc2946a18..a5a5a0d99 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-fees.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-fees.ts @@ -17,7 +17,7 @@ /** * Imports. */ -import { BankAccessApiClient, j2s } from "@gnu-taler/taler-util"; +import { TalerCorebankApiClient, j2s } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { CoinConfig } from "../harness/denomStructures.js"; import { @@ -107,7 +107,7 @@ export async function runWithdrawalFeesTest(t: GlobalTestState) { const amount = "TESTKUDOS:7.5"; - const bankAccessApiClient = new BankAccessApiClient( + const bankAccessApiClient = new TalerCorebankApiClient( bank.bankAccessApiBaseUrl, ); const user = await bankAccessApiClient.createRandomBankUser(); diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-manual.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-manual.ts index 1d98cd46e..316e3cc18 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-manual.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-manual.ts @@ -19,7 +19,7 @@ */ import { AbsoluteTime, - BankAccessApiClient, + TalerCorebankApiClient, Logger, WireGatewayApiClient, j2s, @@ -41,7 +41,7 @@ export async function runWithdrawalManualTest(t: GlobalTestState) { // Create a withdrawal operation - const bankAccessApiClient = new BankAccessApiClient( + const bankAccessApiClient = new TalerCorebankApiClient( bank.bankAccessApiBaseUrl, ); diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts index 237d3bf9f..071871837 100644 --- a/packages/taler-harness/src/integrationtests/testrunner.ts +++ b/packages/taler-harness/src/integrationtests/testrunner.ts @@ -43,25 +43,6 @@ import { runExchangeTimetravelTest } from "./test-exchange-timetravel.js"; import { runFeeRegressionTest } from "./test-fee-regression.js"; import { runForcedSelectionTest } from "./test-forced-selection.js"; import { runKycTest } from "./test-kyc.js"; -import { runLibeufinApiBankaccountTest } from "./test-libeufin-api-bankaccount.js"; -import { runLibeufinApiBankconnectionTest } from "./test-libeufin-api-bankconnection.js"; -import { runLibeufinApiFacadeBadRequestTest } from "./test-libeufin-api-facade-bad-request.js"; -import { runLibeufinApiFacadeTest } from "./test-libeufin-api-facade.js"; -import { runLibeufinApiPermissionsTest } from "./test-libeufin-api-permissions.js"; -import { runLibeufinApiSandboxCamtTest } from "./test-libeufin-api-sandbox-camt.js"; -import { runLibeufinApiSandboxTransactionsTest } from "./test-libeufin-api-sandbox-transactions.js"; -import { runLibeufinApiSchedulingTest } from "./test-libeufin-api-scheduling.js"; -import { runLibeufinApiUsersTest } from "./test-libeufin-api-users.js"; -import { runLibeufinBadGatewayTest } from "./test-libeufin-bad-gateway.js"; -import { runLibeufinBasicTest } from "./test-libeufin-basic.js"; -import { runLibeufinC5xTest } from "./test-libeufin-c5x.js"; -import { runLibeufinAnastasisFacadeTest } from "./test-libeufin-facade-anastasis.js"; -import { runLibeufinKeyrotationTest } from "./test-libeufin-keyrotation.js"; -import { runLibeufinNexusBalanceTest } from "./test-libeufin-nexus-balance.js"; -import { runLibeufinRefundMultipleUsersTest } from "./test-libeufin-refund-multiple-users.js"; -import { runLibeufinRefundTest } from "./test-libeufin-refund.js"; -import { runLibeufinSandboxWireTransferCliTest } from "./test-libeufin-sandbox-wire-transfer-cli.js"; -import { runLibeufinTutorialTest } from "./test-libeufin-tutorial.js"; import { runMerchantExchangeConfusionTest } from "./test-merchant-exchange-confusion.js"; import { runMerchantInstancesDeleteTest } from "./test-merchant-instances-delete.js"; import { runMerchantInstancesUrlsTest } from "./test-merchant-instances-urls.js"; @@ -144,25 +125,6 @@ const allTests: TestMainFunction[] = [ runKycTest, runExchangePurseTest, runExchangeDepositTest, - runLibeufinAnastasisFacadeTest, - runLibeufinApiBankaccountTest, - runLibeufinApiBankconnectionTest, - runLibeufinApiFacadeBadRequestTest, - runLibeufinApiFacadeTest, - runLibeufinApiPermissionsTest, - runLibeufinApiSandboxCamtTest, - runLibeufinApiSandboxTransactionsTest, - runLibeufinApiSchedulingTest, - runLibeufinApiUsersTest, - runLibeufinBadGatewayTest, - runLibeufinBasicTest, - runLibeufinC5xTest, - runLibeufinKeyrotationTest, - runLibeufinNexusBalanceTest, - runLibeufinRefundMultipleUsersTest, - runLibeufinRefundTest, - runLibeufinSandboxWireTransferCliTest, - runLibeufinTutorialTest, runMerchantExchangeConfusionTest, runMerchantInstancesDeleteTest, runMerchantInstancesTest, diff --git a/packages/taler-util/src/bank-api-client.ts b/packages/taler-util/src/bank-api-client.ts index cc4123500..164cd333d 100644 --- a/packages/taler-util/src/bank-api-client.ts +++ b/packages/taler-util/src/bank-api-client.ts @@ -146,11 +146,87 @@ export class WireGatewayApiClient { } } +export interface ChallengeContactData { + // E-Mail address + email?: string; + + // Phone number. + phone?: string; +} + +export interface Balance { + amount: AmountString; + credit_debit_indicator: "credit" | "debit"; +} + +export interface RegisterAccountRequest { + // Username + username: string; + + // Password. + password: string; + + // Legal name of the account owner + name: string; + + // Defaults to false. + is_public?: boolean; + + // Is this a taler exchange account? + // If true: + // - incoming transactions to the account that do not + // have a valid reserve public key are automatically + // - the account provides the taler-wire-gateway-api endpoints + // Defaults to false. + is_taler_exchange?: boolean; + + // Addresses where to send the TAN for transactions. + // Currently only used for cashouts. + // If missing, cashouts will fail. + // In the future, might be used for other transactions + // as well. + challenge_contact_data?: ChallengeContactData; + + // 'payto' address pointing a bank account + // external to the libeufin-bank. + // Payments will be sent to this bank account + // when the user wants to convert the local currency + // back to fiat currency outside libeufin-bank. + cashout_payto_uri?: string; + + // Internal payto URI of this bank account. + // Used mostly for testing. + internal_payto_uri?: string; +} + +export interface AccountData { + // Legal name of the account owner. + name: string; + + // Available balance on the account. + balance: Balance; + + // payto://-URI of the account. + payto_uri: string; + + // Number indicating the max debit allowed for the requesting user. + debit_threshold: AmountString; + + contact_data?: ChallengeContactData; + + // 'payto' address pointing the bank account + // where to send cashouts. This field is optional + // because not all the accounts are required to participate + // in the merchants' circuit. One example is the exchange: + // that never cashouts. Registering these accounts can + // be done via the access API. + cashout_payto_uri?: string; +} + /** - * This API look like it belongs to harness - * but it will be nice to have in utils to be used by others + * Client for the Taler corebank API. */ -export class BankAccessApiClient { +export class TalerCorebankApiClient { httpLib: HttpRequestLibrary; constructor( @@ -215,23 +291,22 @@ export class BankAccessApiClient { return await readSuccessResponseJsonOrThrow(resp, codecForAny()); } - async registerAccount( - username: string, - password: string, - options: { - iban?: string; - } = {}, - ): Promise { - const url = new URL("testing/register", this.baseUrl); + /** + * Register a new account and return information about it. + * + * This is a helper, as it does both the registration and the + * account info query. + */ + async registerAccount(username: string, password: string): Promise { + const url = new URL("accounts", this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", body: { username, password, - iban: options?.iban, + name: username, }, }); - let paytoUri = `payto://x-taler-bank/localhost/${username}`; if (resp.status !== 200 && resp.status !== 202 && resp.status !== 204) { logger.error(`${j2s(await resp.json())}`); throw TalerError.fromDetail( @@ -241,31 +316,24 @@ export class BankAccessApiClient { }, ); } - try { - // Pybank has no body, thus this might throw. - const respJson = await resp.json(); - // LibEuFin demobank returns payto URI in response - if (respJson.paytoUri) { - paytoUri = respJson.paytoUri; - } - } catch (e) { - // Do nothing - } + const infoUrl = new URL(`accounts/${username}`, this.baseUrl); + const infoResp = await this.httpLib.fetch(infoUrl.href); + // FIXME: Validate! + const acctInfo: AccountData = await readSuccessResponseJsonOrThrow( + infoResp, + codecForAny(), + ); return { password, username, - accountPaytoUri: paytoUri, + accountPaytoUri: acctInfo.payto_uri, }; } async createRandomBankUser(): Promise { const username = "user-" + encodeCrock(getRandomBytes(10)).toLowerCase(); const password = "pw-" + encodeCrock(getRandomBytes(10)).toLowerCase(); - // FIXME: This is just a temporary workaround, because demobank is running out of short IBANs - const iban = generateIban("DE", 15); - return await this.registerAccount(username, password, { - iban, - }); + return await this.registerAccount(username, password); } async createWithdrawalOperation( diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts index f7bd3d120..87985fa2a 100644 --- a/packages/taler-util/src/wallet-types.ts +++ b/packages/taler-util/src/wallet-types.ts @@ -366,7 +366,7 @@ export const codecForAmountResponse = (): Codec => .property("rawAmount", codecForAmountString()) .build("AmountResponse"); -export interface Balance { +export interface WalletBalance { scopeInfo: ScopeInfo; available: AmountString; pendingIncoming: AmountString; @@ -458,11 +458,11 @@ export type ScopeInfoAuditor = { export type ScopeInfo = ScopeInfoGlobal | ScopeInfoExchange | ScopeInfoAuditor; export interface BalancesResponse { - balances: Balance[]; + balances: WalletBalance[]; } -export const codecForBalance = (): Codec => - buildCodecForObject() +export const codecForBalance = (): Codec => + buildCodecForObject() .property("scopeInfo", codecForAny()) // FIXME .property("available", codecForString()) .property("hasPendingTransactions", codecForBoolean()) diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts index 4d2fa5cd4..1684977d5 100644 --- a/packages/taler-wallet-core/src/dbless.ts +++ b/packages/taler-wallet-core/src/dbless.ts @@ -31,7 +31,7 @@ import { AmountJson, Amounts, AmountString, - BankAccessApiClient, + TalerCorebankApiClient, codecForAny, codecForBankWithdrawalOperationPostResponse, codecForBatchDepositSuccess, @@ -118,7 +118,7 @@ export async function topupReserveWithDemobank( args: TopupReserveWithDemobankArgs, ) { const { http, bankAccessApiBaseUrl, amount, exchangeInfo, reservePub } = args; - const bankClient = new BankAccessApiClient(bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bankAccessApiBaseUrl); const bankUser = await bankClient.createRandomBankUser(); const wopi = await bankClient.createWithdrawalOperation( bankUser.username, diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts index f71d842c7..b5840c3a6 100644 --- a/packages/taler-wallet-core/src/operations/testing.ts +++ b/packages/taler-wallet-core/src/operations/testing.ts @@ -25,6 +25,7 @@ import { IntegrationTestV2Args, Logger, NotificationType, + RegisterAccountRequest, stringToBytes, TestPayResult, TransactionMajorState, @@ -216,17 +217,25 @@ async function confirmBankWithdrawalUri( async function registerRandomBankUser( http: HttpRequestLibrary, - bankAccessApiBaseUrl: string, + corebankApiBaseUrl: string, ): Promise { - const reqUrl = new URL("testing/register", bankAccessApiBaseUrl).href; + const reqUrl = new URL("accounts", corebankApiBaseUrl).href; const randId = makeId(8); + const username = `testuser-${randId.toLowerCase()}`; + const password = `testpw-${randId}`; + const bankUser: BankUser = { - // euFin doesn't allow resource names to have upper case letters. - username: `testuser-${randId.toLowerCase()}`, - password: `testpw-${randId}`, + username, + password, + }; + + const userReq: RegisterAccountRequest = { + username, + password, + name: username, }; - const resp = await http.postJson(reqUrl, bankUser); + const resp = await http.fetch(reqUrl, { method: "POST", body: userReq }); await checkSuccessResponseOrThrow(resp); return bankUser; } diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 9091a92bf..2c4f1ba6f 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -1513,13 +1513,19 @@ async function dispatchRequestInternal( const components = pt.targetPath.split("/"); const creditorAcct = components[components.length - 1]; logger.info(`making testbank transfer to '${creditorAcct}'`); - const fbReq = await ws.http.postJson( - new URL(`${creditorAcct}/admin/add-incoming`, req.bank).href, + const fbReq = await ws.http.fetch( + new URL( + `accounts/${creditorAcct}/taler-wire-gateway/admin/add-incoming`, + req.bank, + ).href, { - amount: Amounts.stringify(amount), - reserve_pub: wres.reservePub, - debit_account: - "payto://x-taler-bank/localhost/testdebtor?receiver-name=Foo", + method: "POST", + body: { + amount: Amounts.stringify(amount), + reserve_pub: wres.reservePub, + debit_account: + "payto://x-taler-bank/localhost/testdebtor?receiver-name=Foo", + }, }, ); const fbResp = await readSuccessResponseJsonOrThrow(fbReq, codecForAny()); -- cgit v1.2.3 From a99156ed22d21c88cddbfa5fb5908d093b32fbf8 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 21 Sep 2023 18:02:36 +0200 Subject: wallet-core,harness: remove separate fakebank withdrawal API --- packages/taler-harness/src/bench1.ts | 6 ++-- packages/taler-harness/src/bench3.ts | 6 ++-- .../integrationtests/test-withdrawal-fakebank.ts | 6 ++-- .../src/integrationtests/test-withdrawal-huge.ts | 6 ++-- packages/taler-wallet-cli/src/index.ts | 23 ------------- packages/taler-wallet-core/src/wallet-api-types.ts | 14 -------- packages/taler-wallet-core/src/wallet.ts | 40 ---------------------- 7 files changed, 12 insertions(+), 89 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-harness/src/bench1.ts b/packages/taler-harness/src/bench1.ts index 618eb683e..f7b42836d 100644 --- a/packages/taler-harness/src/bench1.ts +++ b/packages/taler-harness/src/bench1.ts @@ -96,10 +96,10 @@ export async function runBench1(configJson: any): Promise { logger.trace(`Starting withdrawal amount=${withdrawAmount}`); let start = Date.now(); - await wallet.client.call(WalletApiOperation.WithdrawFakebank, { + await wallet.client.call(WalletApiOperation.WithdrawTestBalance, { amount: b1conf.currency + ":" + withdrawAmount, - bank: b1conf.bank, - exchange: b1conf.exchange, + bankAccessApiBaseUrl: b1conf.bank, + exchangeBaseUrl: b1conf.exchange, }); await wallet.runTaskLoop({ diff --git a/packages/taler-harness/src/bench3.ts b/packages/taler-harness/src/bench3.ts index 0b5371af5..55cd335f2 100644 --- a/packages/taler-harness/src/bench3.ts +++ b/packages/taler-harness/src/bench3.ts @@ -107,10 +107,10 @@ export async function runBench3(configJson: any): Promise { logger.trace(`Starting withdrawal amount=${withdrawAmount}`); let start = Date.now(); - await wallet.client.call(WalletApiOperation.WithdrawFakebank, { + await wallet.client.call(WalletApiOperation.WithdrawTestBalance, { amount: b3conf.currency + ":" + withdrawAmount, - bank: b3conf.bank, - exchange: b3conf.exchange, + bankAccessApiBaseUrl: b3conf.bank, + exchangeBaseUrl: b3conf.exchange, }); await wallet.runTaskLoop({ diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-fakebank.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-fakebank.ts index 7cd0548a5..84b7b37bf 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-fakebank.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-fakebank.ts @@ -79,10 +79,10 @@ export async function runWithdrawalFakebankTest(t: GlobalTestState) { exchangeBaseUrl: exchange.baseUrl, }); - await wallet.client.call(WalletApiOperation.WithdrawFakebank, { - exchange: exchange.baseUrl, + await wallet.client.call(WalletApiOperation.WithdrawTestBalance, { + bankAccessApiBaseUrl: bank.bankAccessApiBaseUrl, + exchangeBaseUrl: exchange.baseUrl, amount: "TESTKUDOS:10", - bank: bank.baseUrl, }); await exchange.runWirewatchOnce(); diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-huge.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-huge.ts index 8777b19e2..0dfc77447 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-huge.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-huge.ts @@ -99,10 +99,10 @@ export async function runWithdrawalHugeTest(t: GlobalTestState) { }); // Results in about 1K coins withdrawn - await wallet.client.call(WalletApiOperation.WithdrawFakebank, { - exchange: exchange.baseUrl, + await wallet.client.call(WalletApiOperation.WithdrawTestBalance, { + exchangeBaseUrl: exchange.baseUrl, amount: "TESTKUDOS:10000", - bank: bank.baseUrl, + bankAccessApiBaseUrl: bank.baseUrl, }); await withdrawalFinishedCond; diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index b37d4974b..e21a8ce35 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -1290,29 +1290,6 @@ advancedCli wallet.stop(); }); -advancedCli - .subcommand("withdrawFakebank", "withdraw-fakebank", { - help: "Withdraw via a fakebank.", - }) - .requiredOption("exchange", ["--exchange"], clk.STRING, { - help: "Base URL of the exchange to use", - }) - .requiredOption("amount", ["--amount"], clk.STRING, { - help: "Amount to withdraw (before fees).", - }) - .requiredOption("bank", ["--bank"], clk.STRING, { - help: "Base URL of the Taler fakebank service.", - }) - .action(async (args) => { - await withWallet(args, async (wallet) => { - await wallet.client.call(WalletApiOperation.WithdrawFakebank, { - amount: args.withdrawFakebank.amount, - bank: args.withdrawFakebank.bank, - exchange: args.withdrawFakebank.exchange, - }); - }); - }); - advancedCli .subcommand("genSegwit", "gen-segwit") .requiredArgument("paytoUri", clk.STRING) diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts index 67c05a42f..3520a05cb 100644 --- a/packages/taler-wallet-core/src/wallet-api-types.ts +++ b/packages/taler-wallet-core/src/wallet-api-types.ts @@ -118,7 +118,6 @@ import { WalletContractData, WalletCoreVersion, WalletCurrencyInfo, - WithdrawFakebankRequest, WithdrawTestBalanceRequest, WithdrawUriInfoResponse, } from "@gnu-taler/taler-util"; @@ -199,7 +198,6 @@ export enum WalletApiOperation { GenerateDepositGroupTxId = "generateDepositGroupTxId", CreateDepositGroup = "createDepositGroup", SetWalletDeviceId = "setWalletDeviceId", - WithdrawFakebank = "withdrawFakebank", ImportDb = "importDb", ExportDb = "exportDb", PreparePeerPushCredit = "preparePeerPushCredit", @@ -934,17 +932,6 @@ export type TestPayOp = { response: TestPayResult; }; -/** - * Make a withdrawal from a fakebank, i.e. - * a bank where test users can be registered freely - * and testing APIs are available. - */ -export type WithdrawFakebankOp = { - op: WalletApiOperation.WithdrawFakebank; - request: WithdrawFakebankRequest; - response: EmptyObject; -}; - /** * Get wallet-internal pending tasks. */ @@ -1040,7 +1027,6 @@ export type ForceRefreshOp = { export type WalletOperations = { [WalletApiOperation.InitWallet]: InitWalletOp; [WalletApiOperation.GetVersion]: GetVersionOp; - [WalletApiOperation.WithdrawFakebank]: WithdrawFakebankOp; [WalletApiOperation.PreparePayForUri]: PreparePayForUriOp; [WalletApiOperation.SharePayment]: SharePaymentOp; [WalletApiOperation.PreparePayForTemplate]: PreparePayForTemplateOp; diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 2c4f1ba6f..75f1a33a9 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -1492,46 +1492,6 @@ async function dispatchRequestInternal( trustedExchanges: [], }; } - case WalletApiOperation.WithdrawFakebank: { - const req = codecForWithdrawFakebankRequest().decode(payload); - const amount = Amounts.parseOrThrow(req.amount); - const details = await getExchangeWithdrawalInfo( - ws, - req.exchange, - amount, - undefined, - ); - const wres = await createManualWithdrawal(ws, { - amount: amount, - exchangeBaseUrl: req.exchange, - }); - const paytoUri = details.exchangePaytoUris[0]; - const pt = parsePaytoUri(paytoUri); - if (!pt) { - throw Error("failed to parse payto URI"); - } - const components = pt.targetPath.split("/"); - const creditorAcct = components[components.length - 1]; - logger.info(`making testbank transfer to '${creditorAcct}'`); - const fbReq = await ws.http.fetch( - new URL( - `accounts/${creditorAcct}/taler-wire-gateway/admin/add-incoming`, - req.bank, - ).href, - { - method: "POST", - body: { - amount: Amounts.stringify(amount), - reserve_pub: wres.reservePub, - debit_account: - "payto://x-taler-bank/localhost/testdebtor?receiver-name=Foo", - }, - }, - ); - const fbResp = await readSuccessResponseJsonOrThrow(fbReq, codecForAny()); - logger.info(`started fakebank withdrawal: ${j2s(fbResp)}`); - return {}; - } case WalletApiOperation.TestCrypto: { return await ws.cryptoApi.hashString({ str: "hello world" }); } -- cgit v1.2.3 From bdd906c88707b2ec8d6d1d4afbd0bba8e3a9a3cd Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sun, 24 Sep 2023 13:01:42 +0200 Subject: adapt to corebank API change, minor refactoring --- packages/taler-harness/src/harness/helpers.ts | 4 +- .../taler-harness/src/integrationtests/test-kyc.ts | 4 +- .../src/integrationtests/test-payment-fault.ts | 4 +- .../integrationtests/test-wallet-notifications.ts | 4 +- .../test-withdrawal-bank-integrated.ts | 4 +- .../src/integrationtests/test-withdrawal-fees.ts | 4 +- packages/taler-util/src/bank-api-client.ts | 8 +- packages/taler-wallet-core/src/dbless.ts | 4 +- .../taler-wallet-core/src/operations/testing.ts | 146 ++++----------------- 9 files changed, 50 insertions(+), 132 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-harness/src/harness/helpers.ts b/packages/taler-harness/src/harness/helpers.ts index 0a864cad3..27980857c 100644 --- a/packages/taler-harness/src/harness/helpers.ts +++ b/packages/taler-harness/src/harness/helpers.ts @@ -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/integrationtests/test-kyc.ts b/packages/taler-harness/src/integrationtests/test-kyc.ts index 2b2b57183..4fc725bc3 100644 --- a/packages/taler-harness/src/integrationtests/test-kyc.ts +++ b/packages/taler-harness/src/integrationtests/test-kyc.ts @@ -331,7 +331,9 @@ export async function runKycTest(t: GlobalTestState) { // Confirm it - await bankClient.confirmWithdrawalOperation(user.username, wop); + await bankClient.confirmWithdrawalOperation(user.username, { + withdrawalOperationId: wop.withdrawal_id, + }); const kycNotificationCond = walletClient.waitForNotificationCond((x) => { if ( diff --git a/packages/taler-harness/src/integrationtests/test-payment-fault.ts b/packages/taler-harness/src/integrationtests/test-payment-fault.ts index ca74a4ad6..8076e2fb4 100644 --- a/packages/taler-harness/src/integrationtests/test-payment-fault.ts +++ b/packages/taler-harness/src/integrationtests/test-payment-fault.ts @@ -153,7 +153,9 @@ export async function runPaymentFaultTest(t: GlobalTestState) { // Confirm it - await bankClient.confirmWithdrawalOperation(user.username, wop); + await bankClient.confirmWithdrawalOperation(user.username, { + withdrawalOperationId: wop.withdrawal_id, + }); await wallet.runUntilDone(); diff --git a/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts b/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts index ae582fe60..2496f4887 100644 --- a/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts +++ b/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts @@ -161,7 +161,9 @@ export async function runWalletNotificationsTest(t: GlobalTestState) { // Confirm it - await bankAccessApiClient.confirmWithdrawalOperation(user.username, wop); + await bankAccessApiClient.confirmWithdrawalOperation(user.username, { + withdrawalOperationId: wop.withdrawal_id, + }); await withdrawalFinishedReceivedPromise; } diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts index 4a2cc7df9..8c8853f4a 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts @@ -129,7 +129,9 @@ export async function runWithdrawalBankIntegratedTest(t: GlobalTestState) { // Confirm it - await bankAccessApiClient.confirmWithdrawalOperation(user.username, wop); + await bankAccessApiClient.confirmWithdrawalOperation(user.username, { + withdrawalOperationId: wop.withdrawal_id, + }); await withdrawalBankConfirmedCond; diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-fees.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-fees.ts index a5a5a0d99..d3df19664 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-fees.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-fees.ts @@ -152,7 +152,9 @@ export async function runWithdrawalFeesTest(t: GlobalTestState) { // Confirm it - await bankAccessApiClient.confirmWithdrawalOperation(user.username, wop); + await bankAccessApiClient.confirmWithdrawalOperation(user.username, { + withdrawalOperationId: wop.withdrawal_id, + }); await wallet.runUntilDone(); // Check balance diff --git a/packages/taler-util/src/bank-api-client.ts b/packages/taler-util/src/bank-api-client.ts index facb02ea8..d42317f91 100644 --- a/packages/taler-util/src/bank-api-client.ts +++ b/packages/taler-util/src/bank-api-client.ts @@ -223,6 +223,10 @@ export interface AccountData { cashout_payto_uri?: string; } +export interface ConfirmWithdrawalArgs { + withdrawalOperationId: string; +} + /** * Client for the Taler corebank API. */ @@ -356,10 +360,10 @@ export class TalerCorebankApiClient { async confirmWithdrawalOperation( username: string, - wopi: WithdrawalOperationInfo, + wopi: ConfirmWithdrawalArgs, ): Promise { const url = new URL( - `accounts/${username}/withdrawals/${wopi.withdrawal_id}/confirm`, + `withdrawals/${wopi.withdrawalOperationId}/confirm`, this.baseUrl, ); logger.info(`confirming withdrawal operation via ${url.href}`); diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts index 1684977d5..0d702a00c 100644 --- a/packages/taler-wallet-core/src/dbless.ts +++ b/packages/taler-wallet-core/src/dbless.ts @@ -142,7 +142,9 @@ export async function topupReserveWithDemobank( httpResp, codecForBankWithdrawalOperationPostResponse(), ); - await bankClient.confirmWithdrawalOperation(bankUser.username, wopi); + await bankClient.confirmWithdrawalOperation(bankUser.username, { + withdrawalOperationId: wopi.withdrawal_id, + }); } export async function withdrawCoin(args: { diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts index b5840c3a6..9b5dd2a19 100644 --- a/packages/taler-wallet-core/src/operations/testing.ts +++ b/packages/taler-wallet-core/src/operations/testing.ts @@ -27,6 +27,7 @@ import { NotificationType, RegisterAccountRequest, stringToBytes, + TalerCorebankApiClient, TestPayResult, TransactionMajorState, TransactionMinorState, @@ -74,16 +75,6 @@ import { getTransactionById, getTransactions } from "./transactions.js"; const logger = new Logger("operations/testing.ts"); -interface BankUser { - username: string; - password: string; -} - -interface BankWithdrawalResponse { - taler_withdraw_uri: string; - withdrawal_id: string; -} - interface MerchantBackendInfo { baseUrl: string; authToken?: string; @@ -103,16 +94,6 @@ function makeId(length: number): string { return result; } -/** - * Helper function to generate the "Authorization" HTTP header. - * FIXME: redundant, put in taler-util - */ -function makeBasicAuthHeader(username: string, password: string): string { - const auth = `${username}:${password}`; - const authEncoded: string = base64FromArrayBuffer(stringToBytes(auth)); - return `Basic ${authEncoded}`; -} - export async function withdrawTestBalance( ws: InternalWalletState, req: WithdrawTestBalanceRequest, @@ -122,15 +103,18 @@ export async function withdrawTestBalance( const bankAccessApiBaseUrl = req.bankAccessApiBaseUrl; logger.trace( - `Registered bank user, bank access base url ${bankAccessApiBaseUrl}`, + `Registering bank user, bank access base url ${bankAccessApiBaseUrl}`, ); - const bankUser = await registerRandomBankUser(ws.http, bankAccessApiBaseUrl); + + const corebankClient = new TalerCorebankApiClient(bankAccessApiBaseUrl); + + const bankUser = await corebankClient.createRandomBankUser(); logger.trace(`Registered bank user ${JSON.stringify(bankUser)}`); - const wresp = await createDemoBankWithdrawalUri( - ws.http, - bankAccessApiBaseUrl, - bankUser, + corebankClient.setAuth(bankUser); + + const wresp = await corebankClient.createWithdrawalOperation( + bankUser.username, amount, ); @@ -140,14 +124,14 @@ export async function withdrawTestBalance( forcedDenomSel: req.forcedDenomSel, }); - await confirmBankWithdrawalUri( - ws.http, - bankAccessApiBaseUrl, - bankUser, - wresp.withdrawal_id, - ); + await corebankClient.confirmWithdrawalOperation(bankUser.username, { + withdrawalOperationId: wresp.withdrawal_id, + }); } +/** + * FIXME: User MerchantApiClient instead. + */ function getMerchantAuthHeader(m: MerchantBackendInfo): Record { if (m.authToken) { return { @@ -158,88 +142,8 @@ function getMerchantAuthHeader(m: MerchantBackendInfo): Record { } /** - * Use the testing API of a demobank to create a taler://withdraw URI - * that the wallet can then use to make a withdrawal. + * FIXME: User MerchantApiClient instead. */ -export async function createDemoBankWithdrawalUri( - http: HttpRequestLibrary, - bankAccessApiBaseUrl: string, - bankUser: BankUser, - amount: AmountString, -): Promise { - const reqUrl = new URL( - `accounts/${bankUser.username}/withdrawals`, - bankAccessApiBaseUrl, - ).href; - const resp = await http.postJson( - reqUrl, - { - amount, - }, - { - headers: { - Authorization: makeBasicAuthHeader( - bankUser.username, - bankUser.password, - ), - }, - }, - ); - const respJson = await readSuccessResponseJsonOrThrow(resp, codecForAny()); - return respJson; -} - -async function confirmBankWithdrawalUri( - http: HttpRequestLibrary, - bankAccessApiBaseUrl: string, - bankUser: BankUser, - withdrawalId: string, -): Promise { - const reqUrl = new URL( - `accounts/${bankUser.username}/withdrawals/${withdrawalId}/confirm`, - bankAccessApiBaseUrl, - ).href; - const resp = await http.postJson( - reqUrl, - {}, - { - headers: { - Authorization: makeBasicAuthHeader( - bankUser.username, - bankUser.password, - ), - }, - }, - ); - await readSuccessResponseJsonOrThrow(resp, codecForAny()); - return; -} - -async function registerRandomBankUser( - http: HttpRequestLibrary, - corebankApiBaseUrl: string, -): Promise { - const reqUrl = new URL("accounts", corebankApiBaseUrl).href; - const randId = makeId(8); - const username = `testuser-${randId.toLowerCase()}`; - const password = `testpw-${randId}`; - - const bankUser: BankUser = { - username, - password, - }; - - const userReq: RegisterAccountRequest = { - username, - password, - name: username, - }; - - const resp = await http.fetch(reqUrl, { method: "POST", body: userReq }); - await checkSuccessResponseOrThrow(resp); - return bankUser; -} - async function refund( http: HttpRequestLibrary, merchantBackend: MerchantBackendInfo, @@ -267,6 +171,9 @@ async function refund( return refundUri; } +/** + * FIXME: User MerchantApiClient instead. + */ async function createOrder( http: HttpRequestLibrary, merchantBackend: MerchantBackendInfo, @@ -296,6 +203,9 @@ async function createOrder( return { orderId }; } +/** + * FIXME: User MerchantApiClient instead. + */ async function checkPayment( http: HttpRequestLibrary, merchantBackend: MerchantBackendInfo, @@ -309,16 +219,6 @@ async function checkPayment( return readSuccessResponseJsonOrThrow(resp, codecForCheckPaymentResponse()); } -interface BankUser { - username: string; - password: string; -} - -interface BankWithdrawalResponse { - taler_withdraw_uri: string; - withdrawal_id: string; -} - async function makePayment( ws: InternalWalletState, merchant: MerchantBackendInfo, -- cgit v1.2.3 From 7b93938e710c8673ae9a0381b8867705ae872d6f Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sun, 24 Sep 2023 21:03:22 +0200 Subject: harness: add libeufin-bank integration test --- packages/taler-harness/src/env-full.ts | 6 +- packages/taler-harness/src/harness/harness.ts | 166 +++++++++++++-- packages/taler-harness/src/harness/helpers.ts | 14 +- .../src/integrationtests/test-bank-api.ts | 6 +- .../src/integrationtests/test-deposit.ts | 4 +- .../integrationtests/test-exchange-management.ts | 6 +- .../integrationtests/test-exchange-timetravel.ts | 6 +- .../src/integrationtests/test-fee-regression.ts | 4 +- .../taler-harness/src/integrationtests/test-kyc.ts | 6 +- .../src/integrationtests/test-libeufin-bank.ts | 222 +++++++++++++++++++++ .../test-merchant-exchange-confusion.ts | 6 +- .../test-merchant-instances-delete.ts | 6 +- .../test-merchant-instances-urls.ts | 6 +- .../integrationtests/test-merchant-instances.ts | 8 +- .../src/integrationtests/test-payment-fault.ts | 4 +- .../src/integrationtests/test-payment-multiple.ts | 6 +- .../src/integrationtests/test-revocation.ts | 6 +- .../test-timetravel-autorefresh.ts | 6 +- .../integrationtests/test-wallet-notifications.ts | 4 +- .../src/integrationtests/test-wallettesting.ts | 4 +- .../test-withdrawal-bank-integrated.ts | 10 +- .../src/integrationtests/testrunner.ts | 2 + packages/taler-util/src/bank-api-client.ts | 41 +++- packages/taler-util/src/talerconfig.ts | 6 +- packages/taler-util/src/wallet-types.ts | 13 +- .../taler-wallet-core/src/operations/testing.ts | 45 +++++ packages/taler-wallet-core/src/wallet-api-types.ts | 12 ++ packages/taler-wallet-core/src/wallet.ts | 7 + 28 files changed, 552 insertions(+), 80 deletions(-) create mode 100644 packages/taler-harness/src/integrationtests/test-libeufin-bank.ts (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-harness/src/env-full.ts b/packages/taler-harness/src/env-full.ts index 210d38e32..bb2cb8c47 100644 --- a/packages/taler-harness/src/env-full.ts +++ b/packages/taler-harness/src/env-full.ts @@ -25,7 +25,7 @@ import { ExchangeService, FakebankService, MerchantService, - getPayto, + generateRandomPayto, } from "./harness/harness.js"; /** @@ -82,7 +82,7 @@ export async function runEnvFull(t: GlobalTestState): Promise { await merchant.addInstanceWithWireAccount({ id: "default", name: "Default Instance", - paytoUris: [getPayto("merchant-default")], + paytoUris: [generateRandomPayto("merchant-default")], defaultWireTransferDelay: Duration.toTalerProtocolDuration( Duration.fromSpec({ minutes: 1 }), ), @@ -91,7 +91,7 @@ export async function runEnvFull(t: GlobalTestState): Promise { await merchant.addInstanceWithWireAccount({ id: "minst1", name: "minst1", - paytoUris: [getPayto("minst1")], + paytoUris: [generateRandomPayto("minst1")], defaultWireTransferDelay: Duration.toTalerProtocolDuration( Duration.fromSpec({ minutes: 1 }), ), diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts index edb0071c8..8f2d40d6e 100644 --- a/packages/taler-harness/src/harness/harness.ts +++ b/packages/taler-harness/src/harness/harness.ts @@ -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 }); @@ -664,7 +665,7 @@ export class FakebankService return { accountName: accountName, accountPassword: password, - accountPaytoUri: getPayto(accountName), + accountPaytoUri: generateRandomPayto(accountName), wireGatewayApiBaseUrl: `http://localhost:${this.bankConfig.httpPort}/accounts/${accountName}/taler-wire-gateway/`, }; } @@ -702,6 +703,140 @@ export class FakebankService } } +/** + * 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 { + const config = new Configuration(); + const testDir = bc.overrideTestDir ?? gc.testDir; + setTalerPaths(config, testDir + "/talerhome"); + config.setString("libeufin-bankdb", "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", "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 bankAccessApiBaseUrl(): string { + return this.baseUrl; + } + + get port() { + return this.bankConfig.httpPort; + } + + async start(): Promise { + 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.bankAccessApiBaseUrl); + for (const acc of this.accounts) { + await bankClient.registerAccount(acc.accountName, acc.accountPassword); + } + } + + async pingUntilAvailable(): Promise { + const url = `http://localhost:${this.bankConfig.httpPort}/config`; + await pingProc(this.proc, url, "libeufin-bank"); + } +} + // Use libeufin bank instead of pybank. const useLibeufinBank = false; @@ -1011,7 +1146,7 @@ export class ExchangeService implements ExchangeServiceInterface { private exchangeConfig: ExchangeConfig, private configFilename: string, private keyPair: EddsaKeyPair, - ) { } + ) {} get name() { return this.exchangeConfig.name; @@ -1367,7 +1502,7 @@ export class MerchantService implements MerchantServiceInterface { private globalState: GlobalTestState, private merchantConfig: MerchantConfig, private configFilename: string, - ) { } + ) {} private currentTimetravelOffsetMs: number | undefined; @@ -1495,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", }, @@ -1658,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); } @@ -1705,7 +1841,7 @@ export class WalletService { constructor( private globalState: GlobalTestState, private opts: WalletServiceOptions, - ) { } + ) {} get socketPath() { const unixPath = path.join( @@ -1814,7 +1950,7 @@ export class WalletClient { return client.call(operation, payload); } - constructor(private args: WalletClientArgs) { } + constructor(private args: WalletClientArgs) {} async connect(): Promise { const waiter = this.waiter; @@ -1881,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); @@ -1966,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)); @@ -1998,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 27980857c..68b7d087c 100644 --- a/packages/taler-harness/src/harness/helpers.ts +++ b/packages/taler-harness/src/harness/helpers.ts @@ -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!"); diff --git a/packages/taler-harness/src/integrationtests/test-bank-api.ts b/packages/taler-harness/src/integrationtests/test-bank-api.ts index 740e89c30..b87a4043b 100644 --- a/packages/taler-harness/src/integrationtests/test-bank-api.ts +++ b/packages/taler-harness/src/integrationtests/test-bank-api.ts @@ -30,7 +30,7 @@ import { ExchangeService, GlobalTestState, MerchantService, - getPayto, + generateRandomPayto, setupDb, } from "../harness/harness.js"; @@ -88,13 +88,13 @@ export async function runBankApiTest(t: GlobalTestState) { 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!"); diff --git a/packages/taler-harness/src/integrationtests/test-deposit.ts b/packages/taler-harness/src/integrationtests/test-deposit.ts index 7e1bb2a5c..d4bfa3da5 100644 --- a/packages/taler-harness/src/integrationtests/test-deposit.ts +++ b/packages/taler-harness/src/integrationtests/test-deposit.ts @@ -23,7 +23,7 @@ import { TransactionMinorState, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { GlobalTestState, getPayto } from "../harness/harness.js"; +import { GlobalTestState, generateRandomPayto } from "../harness/harness.js"; import { createSimpleTestkudosEnvironmentV2, withdrawViaBankV2, @@ -75,7 +75,7 @@ export async function runDepositTest(t: GlobalTestState) { WalletApiOperation.CreateDepositGroup, { amount: "TESTKUDOS:10", - depositPaytoUri: getPayto("foo"), + depositPaytoUri: generateRandomPayto("foo"), transactionId: depositTxId, }, ); diff --git a/packages/taler-harness/src/integrationtests/test-exchange-management.ts b/packages/taler-harness/src/integrationtests/test-exchange-management.ts index 329012e42..fbee50385 100644 --- a/packages/taler-harness/src/integrationtests/test-exchange-management.ts +++ b/packages/taler-harness/src/integrationtests/test-exchange-management.ts @@ -36,7 +36,7 @@ import { GlobalTestState, MerchantService, WalletCli, - getPayto, + generateRandomPayto, setupDb, } from "../harness/harness.js"; @@ -105,13 +105,13 @@ export async function runExchangeManagementTest( 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!"); diff --git a/packages/taler-harness/src/integrationtests/test-exchange-timetravel.ts b/packages/taler-harness/src/integrationtests/test-exchange-timetravel.ts index 2ef7683b3..efa21e1a0 100644 --- a/packages/taler-harness/src/integrationtests/test-exchange-timetravel.ts +++ b/packages/taler-harness/src/integrationtests/test-exchange-timetravel.ts @@ -35,7 +35,7 @@ import { makeNoFeeCoinConfig } from "../harness/denomStructures.js"; import { BankService, ExchangeService, - getPayto, + generateRandomPayto, GlobalTestState, MerchantService, setupDb, @@ -151,13 +151,13 @@ export async function runExchangeTimetravelTest(t: GlobalTestState) { 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!"); diff --git a/packages/taler-harness/src/integrationtests/test-fee-regression.ts b/packages/taler-harness/src/integrationtests/test-fee-regression.ts index 2d84b3a7c..f164606c4 100644 --- a/packages/taler-harness/src/integrationtests/test-fee-regression.ts +++ b/packages/taler-harness/src/integrationtests/test-fee-regression.ts @@ -23,7 +23,7 @@ import { ExchangeService, GlobalTestState, MerchantService, - getPayto, + generateRandomPayto, setupDb, } from "../harness/harness.js"; import { @@ -142,7 +142,7 @@ export async function createMyTestkudosEnvironment( await merchant.addInstanceWithWireAccount({ id: "minst1", name: "minst1", - paytoUris: [getPayto("minst1")], + paytoUris: [generateRandomPayto("minst1")], }); console.log("setup done!"); diff --git a/packages/taler-harness/src/integrationtests/test-kyc.ts b/packages/taler-harness/src/integrationtests/test-kyc.ts index 4fc725bc3..d646995d6 100644 --- a/packages/taler-harness/src/integrationtests/test-kyc.ts +++ b/packages/taler-harness/src/integrationtests/test-kyc.ts @@ -34,7 +34,7 @@ import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js"; import { BankService, ExchangeService, - getPayto, + generateRandomPayto, GlobalTestState, MerchantService, setupDb, @@ -162,7 +162,7 @@ export async function createKycTestkudosEnvironment( await merchant.addInstanceWithWireAccount({ id: "default", name: "Default Instance", - paytoUris: [getPayto("merchant-default")], + paytoUris: [generateRandomPayto("merchant-default")], defaultWireTransferDelay: Duration.toTalerProtocolDuration( Duration.fromSpec({ minutes: 1 }), ), @@ -171,7 +171,7 @@ export async function createKycTestkudosEnvironment( await merchant.addInstanceWithWireAccount({ id: "minst1", name: "minst1", - paytoUris: [getPayto("minst1")], + paytoUris: [generateRandomPayto("minst1")], defaultWireTransferDelay: Duration.toTalerProtocolDuration( Duration.fromSpec({ minutes: 1 }), ), diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-bank.ts b/packages/taler-harness/src/integrationtests/test-libeufin-bank.ts new file mode 100644 index 000000000..66b4c0b80 --- /dev/null +++ b/packages/taler-harness/src/integrationtests/test-libeufin-bank.ts @@ -0,0 +1,222 @@ +/* + 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 + */ + +/** + * Imports. + */ +import { + TalerCorebankApiClient, + CreditDebitIndicator, + WireGatewayApiClient, + createEddsaKeyPair, + encodeCrock, + Logger, + j2s, + NotificationType, + TransactionMajorState, + TransactionMinorState, +} from "@gnu-taler/taler-util"; +import { defaultCoinConfig } from "../harness/denomStructures.js"; +import { + ExchangeService, + GlobalTestState, + LibeufinBankService, + MerchantService, + generateRandomPayto, + generateRandomTestIban, + setupDb, +} from "../harness/harness.js"; +import { createWalletDaemonWithClient } from "../harness/helpers.js"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; + +const logger = new Logger("test-libeufin-bank.ts"); + +/** + * Run test for the basic functionality of libeufin-bank. + */ +export async function runLibeufinBankTest(t: GlobalTestState) { + // Set up test environment + + const db = await setupDb(t); + + const bank = await LibeufinBankService.create(t, { + currency: "TESTKUDOS", + httpPort: 8082, + database: db.connStr, + allowRegistrations: true, + }); + + const exchange = ExchangeService.create(t, { + name: "testexchange-1", + currency: "TESTKUDOS", + httpPort: 8081, + database: db.connStr, + }); + + const merchant = await MerchantService.create(t, { + name: "testmerchant-1", + currency: "TESTKUDOS", + httpPort: 8083, + database: db.connStr, + }); + + const exchangeIban = generateRandomTestIban(); + const exchangeBankUsername = "exchange"; + const exchangeBankPw = "mypw"; + const exchangePlainPayto = `payto://iban/${exchangeIban}`; + const exchangeExtendedPayto = `payto://iban/${exchangeIban}?receiver-name=Exchange`; + const wireGatewayApiBaseUrl = new URL( + "accounts/exchange/taler-wire-gateway/", + bank.baseUrl, + ).href; + + logger.info("creating bank account for the exchange"); + + exchange.addBankAccount("1", { + wireGatewayApiBaseUrl, + accountName: exchangeBankUsername, + accountPassword: exchangeBankPw, + accountPaytoUri: exchangeExtendedPayto, + }); + + bank.setSuggestedExchange(exchange); + + await bank.start(); + + await bank.pingUntilAvailable(); + + exchange.addOfferedCoins(defaultCoinConfig); + + await exchange.start(); + await exchange.pingUntilAvailable(); + + merchant.addExchange(exchange); + + await merchant.start(); + await merchant.pingUntilAvailable(); + + await merchant.addInstanceWithWireAccount({ + id: "default", + name: "Default Instance", + paytoUris: [generateRandomPayto("merchant-default")], + }); + + await merchant.addInstanceWithWireAccount({ + id: "minst1", + name: "minst1", + paytoUris: [generateRandomPayto("minst1")], + }); + + const { walletClient } = await createWalletDaemonWithClient(t, { + name: "wallet", + }); + + console.log("setup done!"); + + const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); + + // register exchange bank account + await bankClient.registerAccountExtended({ + name: "Exchange", + password: exchangeBankPw, + username: exchangeBankUsername, + is_taler_exchange: true, + internal_payto_uri: exchangePlainPayto, + }); + + const bankUser = await bankClient.registerAccount("user1", "pw1"); + bankClient.setAuth({ + username: "user1", + password: "pw1", + }); + + // Make sure that registering twice results in a 409 Conflict + // { + // const e = await t.assertThrowsTalerErrorAsync(async () => { + // await bankClient.registerAccount("user1", "pw2"); + // }); + // t.assertTrue(e.errorDetail.httpStatusCode === 409); + // } + + let balResp = await bankClient.getAccountBalance(bankUser.username); + + console.log(balResp); + + // Check that we got the sign-up bonus. + t.assertAmountEquals(balResp.balance.amount, "TESTKUDOS:100"); + t.assertTrue( + balResp.balance.credit_debit_indicator === CreditDebitIndicator.Credit, + ); + + const res = createEddsaKeyPair(); + + const wireGatewayApiClient = new WireGatewayApiClient(wireGatewayApiBaseUrl, { + auth: { + username: exchangeBankUsername, + password: exchangeBankPw, + }, + }); + + await wireGatewayApiClient.adminAddIncoming({ + amount: "TESTKUDOS:115", + debitAccountPayto: bankUser.accountPaytoUri, + reservePub: encodeCrock(res.eddsaPub), + }); + + balResp = await bankClient.getAccountBalance(bankUser.username); + t.assertAmountEquals(balResp.balance.amount, "TESTKUDOS:15"); + t.assertTrue( + balResp.balance.credit_debit_indicator === CreditDebitIndicator.Debit, + ); + + const wop = await bankClient.createWithdrawalOperation( + bankUser.username, + "TESTKUDOS:10", + ); + + const r1 = await walletClient.client.call( + WalletApiOperation.GetWithdrawalDetailsForUri, + { + talerWithdrawUri: wop.taler_withdraw_uri, + }, + ); + + console.log(j2s(r1)); + + const r2 = await walletClient.client.call( + WalletApiOperation.AcceptBankIntegratedWithdrawal, + { + exchangeBaseUrl: exchange.baseUrl, + talerWithdrawUri: wop.taler_withdraw_uri, + }, + ); + + await walletClient.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: r2.transactionId, + txState: { + major: TransactionMajorState.Pending, + minor: TransactionMinorState.BankConfirmTransfer, + }, + }); + + await bankClient.confirmWithdrawalOperation(bankUser.username, { + withdrawalOperationId: wop.withdrawal_id, + }); + + await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {}); +} + +runLibeufinBankTest.suites = ["fakebank"]; diff --git a/packages/taler-harness/src/integrationtests/test-merchant-exchange-confusion.ts b/packages/taler-harness/src/integrationtests/test-merchant-exchange-confusion.ts index 2f79041d6..35e3267b1 100644 --- a/packages/taler-harness/src/integrationtests/test-merchant-exchange-confusion.ts +++ b/packages/taler-harness/src/integrationtests/test-merchant-exchange-confusion.ts @@ -33,7 +33,7 @@ import { import { BankService, ExchangeService, - getPayto, + generateRandomPayto, GlobalTestState, harnessHttpLib, MerchantService, @@ -112,13 +112,13 @@ export async function createConfusedMerchantTestkudosEnvironment( 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!"); diff --git a/packages/taler-harness/src/integrationtests/test-merchant-instances-delete.ts b/packages/taler-harness/src/integrationtests/test-merchant-instances-delete.ts index ff567d33d..4508b9976 100644 --- a/packages/taler-harness/src/integrationtests/test-merchant-instances-delete.ts +++ b/packages/taler-harness/src/integrationtests/test-merchant-instances-delete.ts @@ -22,7 +22,7 @@ import { ExchangeService, GlobalTestState, MerchantService, - getPayto, + generateRandomPayto, harnessHttpLib, setupDb, } from "../harness/harness.js"; @@ -78,7 +78,7 @@ export async function runMerchantInstancesDeleteTest(t: GlobalTestState) { await merchant.addInstanceWithWireAccount({ id: "default", name: "Default Instance", - paytoUris: [getPayto("merchant-default")], + paytoUris: [generateRandomPayto("merchant-default")], auth: { method: "external", }, @@ -88,7 +88,7 @@ export async function runMerchantInstancesDeleteTest(t: GlobalTestState) { await merchant.addInstanceWithWireAccount({ id: "myinst", name: "Second Instance", - paytoUris: [getPayto("merchant-default")], + paytoUris: [generateRandomPayto("merchant-default")], auth: { method: "external", }, diff --git a/packages/taler-harness/src/integrationtests/test-merchant-instances-urls.ts b/packages/taler-harness/src/integrationtests/test-merchant-instances-urls.ts index 071288b0f..a037a01c5 100644 --- a/packages/taler-harness/src/integrationtests/test-merchant-instances-urls.ts +++ b/packages/taler-harness/src/integrationtests/test-merchant-instances-urls.ts @@ -22,7 +22,7 @@ import { ExchangeService, GlobalTestState, MerchantService, - getPayto, + generateRandomPayto, harnessHttpLib, setupDb, } from "../harness/harness.js"; @@ -74,7 +74,7 @@ export async function runMerchantInstancesUrlsTest(t: GlobalTestState) { name: "My Default Instance", accounts: [ { - payto_uri: getPayto("bar"), + payto_uri: generateRandomPayto("bar"), }, ], auth: { @@ -97,7 +97,7 @@ export async function runMerchantInstancesUrlsTest(t: GlobalTestState) { name: "My Second Instance", accounts: [ { - payto_uri: getPayto("bar"), + payto_uri: generateRandomPayto("bar"), }, ], auth: { diff --git a/packages/taler-harness/src/integrationtests/test-merchant-instances.ts b/packages/taler-harness/src/integrationtests/test-merchant-instances.ts index 27de8a0a0..a77e9ca51 100644 --- a/packages/taler-harness/src/integrationtests/test-merchant-instances.ts +++ b/packages/taler-harness/src/integrationtests/test-merchant-instances.ts @@ -23,7 +23,7 @@ import { GlobalTestState, MerchantService, setupDb, - getPayto, + generateRandomPayto, harnessHttpLib, } from "../harness/harness.js"; @@ -78,7 +78,7 @@ export async function runMerchantInstancesTest(t: GlobalTestState) { await merchant.addInstanceWithWireAccount({ id: "default", name: "Default Instance", - paytoUris: [getPayto("merchant-default")], + paytoUris: [generateRandomPayto("merchant-default")], auth: { method: "external", }, @@ -88,7 +88,7 @@ export async function runMerchantInstancesTest(t: GlobalTestState) { await merchant.addInstanceWithWireAccount({ id: "default", name: "Default Instance", - paytoUris: [getPayto("merchant-default")], + paytoUris: [generateRandomPayto("merchant-default")], auth: { method: "external", }, @@ -98,7 +98,7 @@ export async function runMerchantInstancesTest(t: GlobalTestState) { await merchant.addInstanceWithWireAccount({ id: "myinst", name: "Second Instance", - paytoUris: [getPayto("merchant-default")], + paytoUris: [generateRandomPayto("merchant-default")], auth: { method: "external", }, diff --git a/packages/taler-harness/src/integrationtests/test-payment-fault.ts b/packages/taler-harness/src/integrationtests/test-payment-fault.ts index 8076e2fb4..63244a4e3 100644 --- a/packages/taler-harness/src/integrationtests/test-payment-fault.ts +++ b/packages/taler-harness/src/integrationtests/test-payment-fault.ts @@ -39,7 +39,7 @@ import { GlobalTestState, MerchantService, WalletCli, - getPayto, + generateRandomPayto, setupDb, } from "../harness/harness.js"; @@ -116,7 +116,7 @@ export async function runPaymentFaultTest(t: GlobalTestState) { await merchant.addInstanceWithWireAccount({ id: "default", name: "Default Instance", - paytoUris: [getPayto("merchant-default")], + paytoUris: [generateRandomPayto("merchant-default")], }); const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl()); diff --git a/packages/taler-harness/src/integrationtests/test-payment-multiple.ts b/packages/taler-harness/src/integrationtests/test-payment-multiple.ts index 4ef5e3bff..0caa3c3e7 100644 --- a/packages/taler-harness/src/integrationtests/test-payment-multiple.ts +++ b/packages/taler-harness/src/integrationtests/test-payment-multiple.ts @@ -25,7 +25,7 @@ import { ExchangeService, GlobalTestState, MerchantService, - getPayto, + generateRandomPayto, setupDb, } from "../harness/harness.js"; import { @@ -87,13 +87,13 @@ async function setupTest(t: GlobalTestState): Promise<{ 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!"); diff --git a/packages/taler-harness/src/integrationtests/test-revocation.ts b/packages/taler-harness/src/integrationtests/test-revocation.ts index 0cb6987ad..9ed2d6206 100644 --- a/packages/taler-harness/src/integrationtests/test-revocation.ts +++ b/packages/taler-harness/src/integrationtests/test-revocation.ts @@ -27,7 +27,7 @@ import { setupDb, BankService, delayMs, - getPayto, + generateRandomPayto, WalletClient, } from "../harness/harness.js"; import { @@ -125,13 +125,13 @@ async function createTestEnvironment( 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!"); diff --git a/packages/taler-harness/src/integrationtests/test-timetravel-autorefresh.ts b/packages/taler-harness/src/integrationtests/test-timetravel-autorefresh.ts index b94f7757c..449142809 100644 --- a/packages/taler-harness/src/integrationtests/test-timetravel-autorefresh.ts +++ b/packages/taler-harness/src/integrationtests/test-timetravel-autorefresh.ts @@ -32,7 +32,7 @@ import { makeNoFeeCoinConfig } from "../harness/denomStructures.js"; import { BankService, ExchangeService, - getPayto, + generateRandomPayto, GlobalTestState, MerchantService, setupDb, @@ -97,13 +97,13 @@ export async function runTimetravelAutorefreshTest(t: GlobalTestState) { 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!"); diff --git a/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts b/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts index 2496f4887..0b5bc45ef 100644 --- a/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts +++ b/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts @@ -32,7 +32,7 @@ import { MerchantService, WalletClient, WalletService, - getRandomIban, + generateRandomTestIban, setupDb, } from "../harness/harness.js"; @@ -94,7 +94,7 @@ export async function runWalletNotificationsTest(t: GlobalTestState) { id: "default", name: "Default Instance", paytoUris: [ - `payto://iban/SANDBOXX/${getRandomIban(label)}?receiver-name=${label}`, + `payto://iban/SANDBOXX/${generateRandomTestIban(label)}?receiver-name=${label}`, ], defaultWireTransferDelay: Duration.toTalerProtocolDuration( Duration.fromSpec({ minutes: 1 }), diff --git a/packages/taler-harness/src/integrationtests/test-wallettesting.ts b/packages/taler-harness/src/integrationtests/test-wallettesting.ts index 4fa870f1c..6d58ae1f2 100644 --- a/packages/taler-harness/src/integrationtests/test-wallettesting.ts +++ b/packages/taler-harness/src/integrationtests/test-wallettesting.ts @@ -32,7 +32,7 @@ import { MerchantService, setupDb, WalletCli, - getPayto, + generateRandomPayto, } from "../harness/harness.js"; import { SimpleTestEnvironment } from "../harness/helpers.js"; @@ -94,7 +94,7 @@ export async function createMyEnvironment( await merchant.addInstanceWithWireAccount({ id: "default", name: "Default Instance", - paytoUris: [getPayto("merchant-default")], + paytoUris: [generateRandomPayto("merchant-default")], }); console.log("setup done!"); diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts index 8c8853f4a..817da5865 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts @@ -41,12 +41,12 @@ export async function runWithdrawalBankIntegratedTest(t: GlobalTestState) { // Create a withdrawal operation - const bankAccessApiClient = new TalerCorebankApiClient( + const corebankApiClient = new TalerCorebankApiClient( bank.bankAccessApiBaseUrl, ); - const user = await bankAccessApiClient.createRandomBankUser(); - bankAccessApiClient.setAuth(user); - const wop = await bankAccessApiClient.createWithdrawalOperation( + const user = await corebankApiClient.createRandomBankUser(); + corebankApiClient.setAuth(user); + const wop = await corebankApiClient.createWithdrawalOperation( user.username, "TESTKUDOS:10", ); @@ -129,7 +129,7 @@ export async function runWithdrawalBankIntegratedTest(t: GlobalTestState) { // Confirm it - await bankAccessApiClient.confirmWithdrawalOperation(user.username, { + await corebankApiClient.confirmWithdrawalOperation(user.username, { withdrawalOperationId: wop.withdrawal_id, }); diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts index 071871837..cf5691fe3 100644 --- a/packages/taler-harness/src/integrationtests/testrunner.ts +++ b/packages/taler-harness/src/integrationtests/testrunner.ts @@ -92,6 +92,7 @@ import { runWithdrawalFeesTest } from "./test-withdrawal-fees.js"; import { runWithdrawalHugeTest } from "./test-withdrawal-huge.js"; import { runWithdrawalManualTest } from "./test-withdrawal-manual.js"; import { runWalletGenDbTest } from "./test-wallet-gendb.js"; +import { runLibeufinBankTest } from "./test-libeufin-bank.js"; /** * Test runner. @@ -173,6 +174,7 @@ const allTests: TestMainFunction[] = [ runStoredBackupsTest, runPaymentExpiredTest, runWalletGenDbTest, + runLibeufinBankTest, ]; export interface TestRunSpec { diff --git a/packages/taler-util/src/bank-api-client.ts b/packages/taler-util/src/bank-api-client.ts index d42317f91..a8cd4b0da 100644 --- a/packages/taler-util/src/bank-api-client.ts +++ b/packages/taler-util/src/bank-api-client.ts @@ -264,7 +264,7 @@ export class TalerCorebankApiClient { const resp = await this.httpLib.fetch(url.href, { headers: this.makeAuthHeader(), }); - return await resp.json(); + return readSuccessResponseJsonOrThrow(resp, codecForAny()); } async getTransactions(username: string): Promise { @@ -295,6 +295,30 @@ export class TalerCorebankApiClient { return await readSuccessResponseJsonOrThrow(resp, codecForAny()); } + async registerAccountExtended(req: RegisterAccountRequest): Promise { + const url = new URL("accounts", this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body: req, + }); + + if ( + resp.status !== 200 && + resp.status !== 201 && + resp.status !== 202 && + resp.status !== 204 + ) { + logger.error(`unexpected status ${resp.status} from POST ${url.href}`); + logger.error(`${j2s(await resp.json())}`); + throw TalerError.fromDetail( + TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR, + { + httpStatusCode: resp.status, + }, + ); + } + } + /** * Register a new account and return information about it. * @@ -311,7 +335,13 @@ export class TalerCorebankApiClient { name: username, }, }); - if (resp.status !== 200 && resp.status !== 202 && resp.status !== 204) { + if ( + resp.status !== 200 && + resp.status !== 201 && + resp.status !== 202 && + resp.status !== 204 + ) { + logger.error(`unexpected status ${resp.status} from POST ${url.href}`); logger.error(`${j2s(await resp.json())}`); throw TalerError.fromDetail( TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR, @@ -320,8 +350,13 @@ export class TalerCorebankApiClient { }, ); } + // FIXME: Corebank should directly return this info! const infoUrl = new URL(`accounts/${username}`, this.baseUrl); - const infoResp = await this.httpLib.fetch(infoUrl.href); + const infoResp = await this.httpLib.fetch(infoUrl.href, { + headers: { + Authorization: makeBasicAuthHeader(username, password), + }, + }); // FIXME: Validate! const acctInfo: AccountData = await readSuccessResponseJsonOrThrow( infoResp, diff --git a/packages/taler-util/src/talerconfig.ts b/packages/taler-util/src/talerconfig.ts index e9eb71279..f817d9bcb 100644 --- a/packages/taler-util/src/talerconfig.ts +++ b/packages/taler-util/src/talerconfig.ts @@ -143,9 +143,9 @@ export function expandPath(path: string): string { export function pathsub( x: string, lookup: (s: string, depth: number) => string | undefined, - depth = 0, + recursionDepth = 0, ): string { - if (depth >= 128) { + if (recursionDepth >= 128) { throw Error("recursion in path substitution"); } let s = x; @@ -201,7 +201,7 @@ export function pathsub( } else { const m = /^[a-zA-Z-_][a-zA-Z0-9-_]*/.exec(s.substring(l + 1)); if (m && m[0]) { - const r = lookup(m[0], depth + 1); + const r = lookup(m[0], recursionDepth + 1); if (r !== undefined) { s = s.substring(0, l) + r + s.substring(l + 1 + m[0].length); l = l + r.length; diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts index 87985fa2a..c5c2c375c 100644 --- a/packages/taler-util/src/wallet-types.ts +++ b/packages/taler-util/src/wallet-types.ts @@ -73,7 +73,13 @@ import { codecForAbsoluteTime, codecForTimestamp, } from "./time.js"; -import { OrderShortInfo, TransactionType } from "./transactions-types.js"; +import { + OrderShortInfo, + TransactionMajorState, + TransactionMinorState, + TransactionState, + TransactionType, +} from "./transactions-types.js"; /** * Identifier for a transaction in the wallet. @@ -2715,3 +2721,8 @@ export interface WalletContractData { maxDepositFee: AmountString; minimumAge?: number; } + +export interface TestingWaitTransactionRequest { + transactionId: string; + txState: TransactionState; +} diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts index 9b5dd2a19..b21f1992c 100644 --- a/packages/taler-wallet-core/src/operations/testing.ts +++ b/packages/taler-wallet-core/src/operations/testing.ts @@ -23,6 +23,7 @@ import { ConfirmPayResultType, Duration, IntegrationTestV2Args, + j2s, Logger, NotificationType, RegisterAccountRequest, @@ -31,6 +32,7 @@ import { TestPayResult, TransactionMajorState, TransactionMinorState, + TransactionState, TransactionType, WithdrawTestBalanceRequest, } from "@gnu-taler/taler-util"; @@ -494,6 +496,49 @@ async function waitUntilPendingReady( cancelNotifs(); } +/** + * Wait until a transaction is in a particular state. + */ +export async function waitTransactionState( + ws: InternalWalletState, + transactionId: string, + txState: TransactionState, +): Promise { + logger.info( + `starting waiting for ${transactionId} to be in ${JSON.stringify( + txState, + )})`, + ); + ws.ensureTaskLoopRunning(); + let p: OpenedPromise | undefined = undefined; + const cancelNotifs = ws.addNotificationListener((notif) => { + if (!p) { + return; + } + if (notif.type === NotificationType.TransactionStateTransition) { + p.resolve(); + } + }); + while (1) { + p = openPromise(); + const tx = await getTransactionById(ws, { + transactionId, + }); + if ( + tx.txState.major === txState.major && + tx.txState.minor === txState.minor + ) { + break; + } + // Wait until transaction state changed + await p.promise; + } + logger.info( + `done waiting for ${transactionId} to be in ${JSON.stringify(txState)}`, + ); + cancelNotifs(); +} + export async function runIntegrationTest2( ws: InternalWalletState, args: IntegrationTestV2Args, diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts index 3520a05cb..6d66e7ad3 100644 --- a/packages/taler-wallet-core/src/wallet-api-types.ts +++ b/packages/taler-wallet-core/src/wallet-api-types.ts @@ -104,6 +104,7 @@ import { TestPayArgs, TestPayResult, TestingSetTimetravelRequest, + TestingWaitTransactionRequest, Transaction, TransactionByIdRequest, TransactionsRequest, @@ -214,6 +215,7 @@ export enum WalletApiOperation { ValidateIban = "validateIban", TestingWaitTransactionsFinal = "testingWaitTransactionsFinal", TestingWaitRefreshesFinal = "testingWaitRefreshesFinal", + TestingWaitTransactionState = "testingWaitTransactionState", TestingSetTimetravel = "testingSetTimetravel", GetScopedCurrencyInfo = "getScopedCurrencyInfo", ListStoredBackups = "listStoredBackups", @@ -1004,6 +1006,15 @@ export type TestingWaitRefreshesFinal = { response: EmptyObject; }; +/** + * Wait until a transaction is in a particular state. + */ +export type TestingWaitTransactionStateOp = { + op: WalletApiOperation.TestingWaitTransactionState; + request: TestingWaitTransactionRequest; + response: EmptyObject; +}; + /** * Set a coin as (un-)suspended. * Suspended coins won't be used for payments. @@ -1108,6 +1119,7 @@ export type WalletOperations = { [WalletApiOperation.TestingWaitTransactionsFinal]: TestingWaitTransactionsFinal; [WalletApiOperation.TestingWaitRefreshesFinal]: TestingWaitRefreshesFinal; [WalletApiOperation.TestingSetTimetravel]: TestingSetTimetravelOp; + [WalletApiOperation.TestingWaitTransactionState]: TestingWaitTransactionStateOp; [WalletApiOperation.GetScopedCurrencyInfo]: GetScopedCurrencyInfoOp; [WalletApiOperation.CreateStoredBackup]: CreateStoredBackupsOp; [WalletApiOperation.ListStoredBackups]: ListStoredBackupsOp; diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 75f1a33a9..ccc7ec094 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -127,6 +127,7 @@ import { codecForRecoverStoredBackupRequest, codecForTestingSetTimetravelRequest, setDangerousTimetravel, + TestingWaitTransactionRequest, } from "@gnu-taler/taler-util"; import type { HttpRequestLibrary } from "@gnu-taler/taler-util/http"; import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; @@ -250,6 +251,7 @@ import { runIntegrationTest, runIntegrationTest2, testPay, + waitTransactionState, waitUntilDone, waitUntilRefreshesDone, withdrawTestBalance, @@ -1414,6 +1416,11 @@ async function dispatchRequestInternal( const resp = await getBackupRecovery(ws); return resp; } + case WalletApiOperation.TestingWaitTransactionState: { + const req = payload as TestingWaitTransactionRequest; + await waitTransactionState(ws, req.transactionId, req.txState); + return {}; + } case WalletApiOperation.GetScopedCurrencyInfo: { // Ignore result, just validate in this mock implementation codecForGetCurrencyInfoRequest().decode(payload); -- cgit v1.2.3 From e628ca1af851259e609a16d0b53b8d7abfc33716 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 25 Sep 2023 19:46:47 +0200 Subject: change demo/test bank URL --- packages/taler-harness/src/index.ts | 4 ++-- packages/taler-wallet-cli/src/index.ts | 2 +- packages/taler-wallet-core/src/wallet.ts | 2 +- packages/taler-wallet-embedded/src/wallet-qjs.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts index 8ace45a89..1f5156b57 100644 --- a/packages/taler-harness/src/index.ts +++ b/packages/taler-harness/src/index.ts @@ -313,7 +313,7 @@ deploymentCli await topupReserveWithDemobank({ amount: "KUDOS:10", bankAccessApiBaseUrl: - "https://bank.demo.taler.net/demobanks/default/access-api/", + "https://bank.demo.taler.net/", exchangeInfo, http, reservePub: reserveKeyPair.pub, @@ -342,7 +342,7 @@ deploymentCli await topupReserveWithDemobank({ amount: "TESTKUDOS:10", bankAccessApiBaseUrl: - "https://bank.test.taler.net/demobanks/default/access-api/", + "https://bank.test.taler.net/", exchangeInfo, http, reservePub: reserveKeyPair.pub, diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index e21a8ce35..bfc259481 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -1508,7 +1508,7 @@ testCli.subcommand("withdrawKudos", "withdraw-kudos").action(async (args) => { await wallet.client.call(WalletApiOperation.WithdrawTestBalance, { amount: "KUDOS:50", bankAccessApiBaseUrl: - "https://bank.demo.taler.net/demobanks/default/access-api/", + "https://bank.demo.taler.net/", exchangeBaseUrl: "https://exchange.demo.taler.net/", }); }); diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index ccc7ec094..496297021 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -1072,7 +1072,7 @@ async function dispatchRequestInternal( await withdrawTestBalance(ws, { amount: "TESTKUDOS:10", bankAccessApiBaseUrl: - "https://bank.test.taler.net/demobanks/default/access-api/", + "https://bank.test.taler.net/", exchangeBaseUrl: "https://exchange.test.taler.net/", }); return { diff --git a/packages/taler-wallet-embedded/src/wallet-qjs.ts b/packages/taler-wallet-embedded/src/wallet-qjs.ts index 5e2f1e0a4..e0888aa8a 100644 --- a/packages/taler-wallet-embedded/src/wallet-qjs.ts +++ b/packages/taler-wallet-embedded/src/wallet-qjs.ts @@ -279,7 +279,7 @@ export async function testWithGv() { amountToSpend: "KUDOS:1", amountToWithdraw: "KUDOS:3", bankAccessApiBaseUrl: - "https://bank.demo.taler.net/demobanks/default/access-api/", + "https://bank.demo.taler.net/", exchangeBaseUrl: "https://exchange.demo.taler.net/", merchantBaseUrl: "https://backend.demo.taler.net/", }); -- cgit v1.2.3 From ae49194d4271f1108ec9b8318ea3b7977314cb85 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 08:40:18 -0300 Subject: more ui --- .../demobank-ui/src/components/ErrorLoading.tsx | 19 +++++-- packages/demobank-ui/src/components/Routing.tsx | 4 +- .../src/components/Transactions/views.tsx | 1 + packages/demobank-ui/src/hooks/access.ts | 2 +- .../demobank-ui/src/pages/AccountPage/index.ts | 10 ++-- .../demobank-ui/src/pages/AccountPage/state.ts | 7 +++ packages/demobank-ui/src/pages/BankFrame.tsx | 5 +- packages/demobank-ui/src/pages/HomePage.tsx | 8 +-- packages/demobank-ui/src/pages/LoginForm.tsx | 4 +- .../demobank-ui/src/pages/OperationState/index.ts | 11 ++-- .../demobank-ui/src/pages/OperationState/state.ts | 36 ++++++++++---- .../demobank-ui/src/pages/OperationState/views.tsx | 44 ++++++---------- packages/demobank-ui/src/pages/PaymentOptions.tsx | 4 +- .../demobank-ui/src/pages/RegistrationPage.tsx | 58 +++++++++++++++++++--- packages/demobank-ui/src/pages/Test.tsx | 5 -- .../demobank-ui/src/pages/WalletWithdrawForm.tsx | 1 - packages/taler-util/src/errors.ts | 2 +- .../taler-wallet-core/src/operations/withdraw.ts | 17 +++---- packages/taler-wallet-core/src/versions.ts | 2 +- 19 files changed, 145 insertions(+), 95 deletions(-) delete mode 100644 packages/demobank-ui/src/pages/Test.tsx (limited to 'packages/taler-wallet-core') diff --git a/packages/demobank-ui/src/components/ErrorLoading.tsx b/packages/demobank-ui/src/components/ErrorLoading.tsx index fbc4ffceb..a4faa4d5d 100644 --- a/packages/demobank-ui/src/components/ErrorLoading.tsx +++ b/packages/demobank-ui/src/components/ErrorLoading.tsx @@ -15,15 +15,24 @@ GNU Taler; see the file COPYING. If not, see */ -import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { HttpError, useTranslationContext } from "@gnu-taler/web-util/browser"; import { h, VNode } from "preact"; -export function ErrorLoading(): VNode { +export function ErrorLoading({ error }: { error: HttpError }): VNode { const { i18n } = useTranslationContext() return ( -
- Could not complete the request - +
+
+
+ +
+
+

{error.message}

+
+
+
); } diff --git a/packages/demobank-ui/src/components/Routing.tsx b/packages/demobank-ui/src/components/Routing.tsx index d51bd01eb..2710069c2 100644 --- a/packages/demobank-ui/src/components/Routing.tsx +++ b/packages/demobank-ui/src/components/Routing.tsx @@ -23,7 +23,6 @@ import { BusinessAccount } from "../pages/business/Home.js"; import { HomePage, WithdrawalOperationPage } from "../pages/HomePage.js"; import { PublicHistoriesPage } from "../pages/PublicHistoriesPage.js"; import { RegistrationPage } from "../pages/RegistrationPage.js"; -import { Test } from "../pages/Test.js"; import { useBackendContext } from "../context/backend.js"; import { LoginForm } from "../pages/LoginForm.js"; import { AdminHome } from "../pages/admin/Home.js"; @@ -69,6 +68,9 @@ export function Routing(): VNode { onComplete={() => { route("/account"); }} + onCancel={() => { + route("/account"); + }} /> )} /> diff --git a/packages/demobank-ui/src/components/Transactions/views.tsx b/packages/demobank-ui/src/components/Transactions/views.tsx index b11888320..e34120e34 100644 --- a/packages/demobank-ui/src/components/Transactions/views.tsx +++ b/packages/demobank-ui/src/components/Transactions/views.tsx @@ -32,6 +32,7 @@ export function LoadingUriView({ error }: State.LoadingUriError): VNode { export function ReadyView({ transactions }: State.Ready): VNode { const { i18n } = useTranslationContext(); + if (!transactions.length) return
const txByDate = transactions.reduce((prev, cur) => { const d = cur.when.t_ms === "never" ? "" diff --git a/packages/demobank-ui/src/hooks/access.ts b/packages/demobank-ui/src/hooks/access.ts index 13fee71f0..2f6848af8 100644 --- a/packages/demobank-ui/src/hooks/access.ts +++ b/packages/demobank-ui/src/hooks/access.ts @@ -94,7 +94,7 @@ export function useAccessAnonAPI(): AccessAnonAPI { const { request } = useAuthenticatedBackend(); const abortWithdrawal = async (id: string): Promise> => { - const res = await request(`accounts/withdrawals/${id}/abort`, { + const res = await request(`withdrawals/${id}/abort`, { method: "POST", contentType: "json", }); diff --git a/packages/demobank-ui/src/pages/AccountPage/index.ts b/packages/demobank-ui/src/pages/AccountPage/index.ts index ba9b85710..9230fb6b1 100644 --- a/packages/demobank-ui/src/pages/AccountPage/index.ts +++ b/packages/demobank-ui/src/pages/AccountPage/index.ts @@ -18,7 +18,7 @@ import { HttpError, HttpResponseOk, HttpResponsePaginated, utils } from "@gnu-ta import { AbsoluteTime, AmountJson, PaytoUriIBAN, PaytoUriTalerBank } from "@gnu-taler/taler-util"; import { Loading } from "../../components/Loading.js"; import { useComponentState } from "./state.js"; -import { ReadyView, InvalidIbanView} from "./views.js"; +import { ReadyView, InvalidIbanView } from "./views.js"; import { VNode } from "preact"; import { LoginForm } from "../LoginForm.js"; import { ErrorLoading } from "../../components/ErrorLoading.js"; @@ -29,7 +29,7 @@ export interface Props { error: HttpResponsePaginated, ) => VNode; goToBusinessAccount: () => void; - goToConfirmOperation: (id:string) => void; + goToConfirmOperation: (id: string) => void; } export type State = State.Loading | State.LoadingError | State.Ready | State.InvalidIban | State.UserNotFound; @@ -48,14 +48,14 @@ export namespace State { export interface BaseInfo { error: undefined; } - + export interface Ready extends BaseInfo { status: "ready"; error: undefined; - account: string, + account: string, limit: AmountJson, goToBusinessAccount: () => void; - goToConfirmOperation: (id:string) => void; + goToConfirmOperation: (id: string) => void; } export interface InvalidIban { diff --git a/packages/demobank-ui/src/pages/AccountPage/state.ts b/packages/demobank-ui/src/pages/AccountPage/state.ts index b12afbf9e..3df463f4e 100644 --- a/packages/demobank-ui/src/pages/AccountPage/state.ts +++ b/packages/demobank-ui/src/pages/AccountPage/state.ts @@ -48,6 +48,13 @@ export function useComponentState({ account, goToBusinessAccount, goToConfirmOpe error: result, }; } + if (result.status === HttpStatusCode.Unauthorized) { + notifyError(i18n.str`Require login`, undefined); + return { + status: "error-user-not-found", + error: result, + }; + } return { status: "loading-error", error: result, diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx b/packages/demobank-ui/src/pages/BankFrame.tsx index a1414544e..214aac063 100644 --- a/packages/demobank-ui/src/pages/BankFrame.tsx +++ b/packages/demobank-ui/src/pages/BankFrame.tsx @@ -344,8 +344,6 @@ function StatusBanner(): VNode { class="fixed top-10 z-20 ml-4 mr-4" > { notifs.map(n => { - const info = n.message.type === "info" ? n.message : undefined - const error = n.message.type === "error" ? n.message : undefined switch (n.message.type) { case "error": return
@@ -478,8 +476,7 @@ function AccountBalance({ account }: { account: string }): VNode { // FIXME: balance return
- {Amounts.currencyOf(result.data.balance)} - {Amounts.stringifyValue(result.data.balance)} + {Amounts.currencyOf(result.data.balance)} {Amounts.stringifyValue(result.data.balance)} {/* {Amounts.currencyOf(result.data.balance.amount)}  {result.data.balance.credit_debit_indicator === "debit" ? "-" : ""} {Amounts.stringifyValue(result.data.balance.amount)} */} diff --git a/packages/demobank-ui/src/pages/HomePage.tsx b/packages/demobank-ui/src/pages/HomePage.tsx index d80a57d21..fb30c1218 100644 --- a/packages/demobank-ui/src/pages/HomePage.tsx +++ b/packages/demobank-ui/src/pages/HomePage.tsx @@ -59,7 +59,7 @@ export function HomePage({ account: string, onRegister: () => void; goToBusinessAccount: () => void; - goToConfirmOperation: (id:string) => void; + goToConfirmOperation: (id: string) => void; }): VNode { const { i18n } = useTranslationContext(); @@ -84,7 +84,7 @@ export function WithdrawalOperationPage({ //or return withdrawal uri from response const baseUrl = getInitialBackendBaseURL() const uri = stringifyWithdrawUri({ - bankIntegrationApiBaseUrl: `${baseUrl}/integration-api`, + bankIntegrationApiBaseUrl: `${baseUrl}/taler-integration`, withdrawalOperationId: operationId, }); const parsedUri = parseWithdrawUri(uri); @@ -98,7 +98,7 @@ export function WithdrawalOperationPage({ ); return ; } - + return ( ( result: | HttpResponsePaginated - | HttpResponse, + | HttpResponse, ): VNode { if (result.loading) return ; if (!result.ok) { diff --git a/packages/demobank-ui/src/pages/LoginForm.tsx b/packages/demobank-ui/src/pages/LoginForm.tsx index 0d4bd1261..cfef71b9a 100644 --- a/packages/demobank-ui/src/pages/LoginForm.tsx +++ b/packages/demobank-ui/src/pages/LoginForm.tsx @@ -49,7 +49,7 @@ export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode { ? i18n.str`Missing username` // : !USERNAME_REGEX.test(username) // ? i18n.str`Use letters and numbers only, and start with a lowercase letter` - : undefined, + : undefined, password: !password ? i18n.str`Missing password` : undefined, }) ?? busy; @@ -213,7 +213,7 @@ export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode { {bankUiSettings.allowRegistrations && onRegister &&

+

@@ -360,39 +370,13 @@ export function ReadyView({ uri, onClose }: State.Ready): VNode<{}> { Scan the QR code with your mobile device.

-
- -
- {show && -
- -
- } +
+ +
-
- -
} diff --git a/packages/demobank-ui/src/pages/PaymentOptions.tsx b/packages/demobank-ui/src/pages/PaymentOptions.tsx index 2830f5c1e..49419d0dc 100644 --- a/packages/demobank-ui/src/pages/PaymentOptions.tsx +++ b/packages/demobank-ui/src/pages/PaymentOptions.tsx @@ -56,11 +56,11 @@ export function PaymentOptions({ limit, goToConfirmOperation }: { limit: AmountJ Withdraw digital money into your mobile wallet or browser extension {!!settings.currentWithdrawalOperationId && - + - Operation in progress + operation ready } diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx b/packages/demobank-ui/src/pages/RegistrationPage.tsx index 8221457bf..5325f43ab 100644 --- a/packages/demobank-ui/src/pages/RegistrationPage.tsx +++ b/packages/demobank-ui/src/pages/RegistrationPage.tsx @@ -33,8 +33,10 @@ const logger = new Logger("RegistrationPage"); export function RegistrationPage({ onComplete, + onCancel }: { onComplete: () => void; + onCancel: () => void; }): VNode { const { i18n } = useTranslationContext(); if (!bankUiSettings.allowRegistrations) { @@ -42,7 +44,7 @@ export function RegistrationPage({

{i18n.str`Currently, the bank is not accepting new registrations!`}

); } - return ; + return ; } export const USERNAME_REGEX = /^[a-z][a-zA-Z0-9-]*$/; @@ -50,7 +52,7 @@ export const USERNAME_REGEX = /^[a-z][a-zA-Z0-9-]*$/; /** * Collect and submit registration data. */ -function RegistrationForm({ onComplete }: { onComplete: () => void }): VNode { +function RegistrationForm({ onComplete, onCancel }: { onComplete: () => void, onCancel: () => void }): VNode { const backend = useBackendContext(); const [username, setUsername] = useState(); const [name, setName] = useState(); @@ -168,9 +170,38 @@ function RegistrationForm({ onComplete }: { onComplete: () => void }): VNode { autoCapitalize="none" autoCorrect="off" > +
+ +
+ { + setName(e.currentTarget.value); + }} + /> + +
+
+
void }): VNode {
- +
void }): VNode {
- +
void }): VNode {
-
+
+
diff --git a/packages/taler-util/src/errors.ts b/packages/taler-util/src/errors.ts index 4399dbcf2..07a402413 100644 --- a/packages/taler-util/src/errors.ts +++ b/packages/taler-util/src/errors.ts @@ -78,7 +78,7 @@ export interface DetailsMap { stack?: string; }; [TalerErrorCode.WALLET_BANK_INTEGRATION_PROTOCOL_VERSION_INCOMPATIBLE]: { - exchangeProtocolVersion: string; + bankProtocolVersion: string; walletProtocolVersion: string; }; [TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN]: { diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index fb503d75f..2c9c95d4c 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -570,7 +570,7 @@ export async function getBankWithdrawalInfo( throw TalerError.fromDetail( TalerErrorCode.WALLET_BANK_INTEGRATION_PROTOCOL_VERSION_INCOMPATIBLE, { - exchangeProtocolVersion: config.version, + bankProtocolVersion: config.version, walletProtocolVersion: WALLET_BANK_INTEGRATION_PROTOCOL_VERSION, }, "bank integration protocol version not compatible with wallet", @@ -813,10 +813,10 @@ async function handleKycRequired( amlStatus === AmlStatus.normal || amlStatus === undefined ? WithdrawalGroupStatus.PendingKyc : amlStatus === AmlStatus.pending - ? WithdrawalGroupStatus.PendingAml - : amlStatus === AmlStatus.fronzen - ? WithdrawalGroupStatus.SuspendedAml - : assertUnreachable(amlStatus); + ? WithdrawalGroupStatus.PendingAml + : amlStatus === AmlStatus.fronzen + ? WithdrawalGroupStatus.SuspendedAml + : assertUnreachable(amlStatus); await tx.withdrawalGroups.put(wg2); const newTxState = computeWithdrawalTransactionStatus(wg2); @@ -1145,8 +1145,7 @@ export async function updateWithdrawalDenoms( denom.verificationStatus === DenominationVerificationStatus.Unverified ) { logger.trace( - `Validating denomination (${current + 1}/${ - denominations.length + `Validating denomination (${current + 1}/${denominations.length }) signature of ${denom.denomPubHash}`, ); let valid = false; @@ -1240,7 +1239,7 @@ async function queryReserve( if ( resp.status === 404 && result.talerErrorResponse.code === - TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN + TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN ) { return { ready: false }; } else { @@ -1775,7 +1774,7 @@ export async function getExchangeWithdrawalInfo( ) { logger.warn( `wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` + - `(exchange has ${exchangeDetails.protocolVersionRange}), checking for updates`, + `(exchange has ${exchangeDetails.protocolVersionRange}), checking for updates`, ); } } diff --git a/packages/taler-wallet-core/src/versions.ts b/packages/taler-wallet-core/src/versions.ts index 8b9177bc3..022f4900d 100644 --- a/packages/taler-wallet-core/src/versions.ts +++ b/packages/taler-wallet-core/src/versions.ts @@ -29,7 +29,7 @@ export const WALLET_EXCHANGE_PROTOCOL_VERSION = "17:0:0"; export const WALLET_MERCHANT_PROTOCOL_VERSION = "2:0:1"; /** - * Protocol version spoken with the merchant. + * Protocol version spoken with the bank. * * Uses libtool's current:revision:age versioning. */ -- cgit v1.2.3 From 256e86fdc00fc950e67a1472e9ba4c15b61d68bb Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 27 Sep 2023 09:22:18 +0200 Subject: add empty migration from previous database version --- packages/taler-harness/package.json | 4 ++-- packages/taler-util/package.json | 4 ++-- packages/taler-wallet-cli/package.json | 4 ++-- packages/taler-wallet-core/package.json | 4 ++-- packages/taler-wallet-core/src/db.ts | 1 + packages/taler-wallet-embedded/package.json | 4 ++-- packages/taler-wallet-webextension/manifest-common.json | 4 ++-- packages/taler-wallet-webextension/package.json | 4 ++-- packages/web-util/package.json | 2 +- 9 files changed, 16 insertions(+), 15 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-harness/package.json b/packages/taler-harness/package.json index 38f168af4..b1a9dc2e5 100644 --- a/packages/taler-harness/package.json +++ b/packages/taler-harness/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-harness", - "version": "0.9.3-dev.17", + "version": "0.9.3-dev.26", "description": "", "engines": { "node": ">=0.12.0" @@ -42,4 +42,4 @@ "@gnu-taler/taler-wallet-core": "workspace:*", "tslib": "^2.5.3" } -} +} \ No newline at end of file diff --git a/packages/taler-util/package.json b/packages/taler-util/package.json index 80e99ae0e..6d80e9823 100644 --- a/packages/taler-util/package.json +++ b/packages/taler-util/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-util", - "version": "0.9.3-dev.17", + "version": "0.9.3-dev.26", "description": "Generic helper functionality for GNU Taler", "type": "module", "types": "./lib/index.node.d.ts", @@ -82,4 +82,4 @@ "lib/**/*test.js" ] } -} +} \ No newline at end of file diff --git a/packages/taler-wallet-cli/package.json b/packages/taler-wallet-cli/package.json index 382951223..0f1b3ea0c 100644 --- a/packages/taler-wallet-cli/package.json +++ b/packages/taler-wallet-cli/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-wallet-cli", - "version": "0.9.3-dev.17", + "version": "0.9.3-dev.26", "description": "", "engines": { "node": ">=0.18.0" @@ -41,4 +41,4 @@ "@gnu-taler/taler-wallet-core": "workspace:*", "tslib": "^2.5.3" } -} +} \ No newline at end of file diff --git a/packages/taler-wallet-core/package.json b/packages/taler-wallet-core/package.json index 668fe4b92..8da42bfdc 100644 --- a/packages/taler-wallet-core/package.json +++ b/packages/taler-wallet-core/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-wallet-core", - "version": "0.9.3-dev.17", + "version": "0.9.3-dev.26", "description": "", "engines": { "node": ">=0.18.0" @@ -84,4 +84,4 @@ "lib/**/*test.*" ] } -} +} \ No newline at end of file diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index a5ead4d64..156651cc6 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -3092,6 +3092,7 @@ export async function openTalerDatabase( case "taler-wallet-main-v6": case "taler-wallet-main-v7": case "taler-wallet-main-v8": + case "taler-wallet-main-v9": // We consider this a pre-release // development version, no migration is done. await metaDb diff --git a/packages/taler-wallet-embedded/package.json b/packages/taler-wallet-embedded/package.json index 35a4fcffe..fff047d6b 100644 --- a/packages/taler-wallet-embedded/package.json +++ b/packages/taler-wallet-embedded/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-wallet-embedded", - "version": "0.9.3-dev.17", + "version": "0.9.3-dev.26", "description": "", "engines": { "node": ">=0.18.0" @@ -39,4 +39,4 @@ "@gnu-taler/anastasis-core": "workspace:*", "tslib": "^2.5.3" } -} +} \ No newline at end of file diff --git a/packages/taler-wallet-webextension/manifest-common.json b/packages/taler-wallet-webextension/manifest-common.json index bb752e1b7..9f8a978a3 100644 --- a/packages/taler-wallet-webextension/manifest-common.json +++ b/packages/taler-wallet-webextension/manifest-common.json @@ -2,8 +2,8 @@ "name": "GNU Taler Wallet (git)", "description": "Privacy preserving and transparent payments", "author": "GNU Taler Developers", - "version": "0.9.3.17", - "version_name": "0.9.3-dev.17", + "version": "0.9.3.26", + "version_name": "0.9.3-dev.26", "icons": { "16": "static/img/taler-logo-16.png", "19": "static/img/taler-logo-19.png", diff --git a/packages/taler-wallet-webextension/package.json b/packages/taler-wallet-webextension/package.json index 23736729c..0b143f90a 100644 --- a/packages/taler-wallet-webextension/package.json +++ b/packages/taler-wallet-webextension/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-wallet-webextension", - "version": "0.9.3-dev.17", + "version": "0.9.3-dev.26", "description": "GNU Taler Wallet browser extension", "main": "./build/index.js", "types": "./build/index.d.ts", @@ -75,4 +75,4 @@ "pogen": { "domain": "taler-wallet-webex" } -} +} \ No newline at end of file diff --git a/packages/web-util/package.json b/packages/web-util/package.json index 2c1b697d8..f09b96038 100644 --- a/packages/web-util/package.json +++ b/packages/web-util/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/web-util", - "version": "0.9.3-dev.17", + "version": "0.9.3-dev.26", "description": "Generic helper functionality for GNU Taler Web Apps", "type": "module", "types": "./lib/index.node.d.ts", -- cgit v1.2.3 From 61424e2cb51dde9a8c7442b20b6621cc8b1d3b26 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 27 Sep 2023 09:22:42 +0200 Subject: bump version --- packages/taler-harness/package.json | 2 +- packages/taler-util/package.json | 2 +- packages/taler-wallet-cli/package.json | 2 +- packages/taler-wallet-core/package.json | 2 +- packages/taler-wallet-embedded/package.json | 2 +- packages/taler-wallet-webextension/manifest-common.json | 4 ++-- packages/taler-wallet-webextension/package.json | 2 +- packages/web-util/package.json | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-harness/package.json b/packages/taler-harness/package.json index b1a9dc2e5..b4896916b 100644 --- a/packages/taler-harness/package.json +++ b/packages/taler-harness/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-harness", - "version": "0.9.3-dev.26", + "version": "0.9.3-dev.27", "description": "", "engines": { "node": ">=0.12.0" diff --git a/packages/taler-util/package.json b/packages/taler-util/package.json index 6d80e9823..7fceb9576 100644 --- a/packages/taler-util/package.json +++ b/packages/taler-util/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-util", - "version": "0.9.3-dev.26", + "version": "0.9.3-dev.27", "description": "Generic helper functionality for GNU Taler", "type": "module", "types": "./lib/index.node.d.ts", diff --git a/packages/taler-wallet-cli/package.json b/packages/taler-wallet-cli/package.json index 0f1b3ea0c..571371b87 100644 --- a/packages/taler-wallet-cli/package.json +++ b/packages/taler-wallet-cli/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-wallet-cli", - "version": "0.9.3-dev.26", + "version": "0.9.3-dev.27", "description": "", "engines": { "node": ">=0.18.0" diff --git a/packages/taler-wallet-core/package.json b/packages/taler-wallet-core/package.json index 8da42bfdc..beef99840 100644 --- a/packages/taler-wallet-core/package.json +++ b/packages/taler-wallet-core/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-wallet-core", - "version": "0.9.3-dev.26", + "version": "0.9.3-dev.27", "description": "", "engines": { "node": ">=0.18.0" diff --git a/packages/taler-wallet-embedded/package.json b/packages/taler-wallet-embedded/package.json index fff047d6b..442a1f962 100644 --- a/packages/taler-wallet-embedded/package.json +++ b/packages/taler-wallet-embedded/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-wallet-embedded", - "version": "0.9.3-dev.26", + "version": "0.9.3-dev.27", "description": "", "engines": { "node": ">=0.18.0" diff --git a/packages/taler-wallet-webextension/manifest-common.json b/packages/taler-wallet-webextension/manifest-common.json index 9f8a978a3..0e333c7a8 100644 --- a/packages/taler-wallet-webextension/manifest-common.json +++ b/packages/taler-wallet-webextension/manifest-common.json @@ -2,8 +2,8 @@ "name": "GNU Taler Wallet (git)", "description": "Privacy preserving and transparent payments", "author": "GNU Taler Developers", - "version": "0.9.3.26", - "version_name": "0.9.3-dev.26", + "version": "0.9.3.27", + "version_name": "0.9.3-dev.27", "icons": { "16": "static/img/taler-logo-16.png", "19": "static/img/taler-logo-19.png", diff --git a/packages/taler-wallet-webextension/package.json b/packages/taler-wallet-webextension/package.json index 0b143f90a..fc91ed4cc 100644 --- a/packages/taler-wallet-webextension/package.json +++ b/packages/taler-wallet-webextension/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/taler-wallet-webextension", - "version": "0.9.3-dev.26", + "version": "0.9.3-dev.27", "description": "GNU Taler Wallet browser extension", "main": "./build/index.js", "types": "./build/index.d.ts", diff --git a/packages/web-util/package.json b/packages/web-util/package.json index f09b96038..5a5203392 100644 --- a/packages/web-util/package.json +++ b/packages/web-util/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/web-util", - "version": "0.9.3-dev.26", + "version": "0.9.3-dev.27", "description": "Generic helper functionality for GNU Taler Web Apps", "type": "module", "types": "./lib/index.node.d.ts", -- cgit v1.2.3 From 671bbf29548e2ec078b29e75e368d77ee7bdb81f Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 2 Oct 2023 22:48:29 +0200 Subject: wallet-core: implement explicit updateExchangeEntry request --- packages/taler-util/src/wallet-types.ts | 9 +++++++++ packages/taler-wallet-core/src/wallet-api-types.ts | 12 ++++++++++++ packages/taler-wallet-core/src/wallet.ts | 9 +++++++-- 3 files changed, 28 insertions(+), 2 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts index c5c2c375c..8fff8ae55 100644 --- a/packages/taler-util/src/wallet-types.ts +++ b/packages/taler-util/src/wallet-types.ts @@ -1601,6 +1601,15 @@ export const codecForAddExchangeRequest = (): Codec => .property("masterPub", codecOptional(codecForString())) .build("AddExchangeRequest"); +export interface UpdateExchangeEntryRequest { + exchangeBaseUrl: string; +} + +export const codecForUpdateExchangeEntryRequest = (): Codec => + buildCodecForObject() + .property("exchangeBaseUrl", codecForString()) + .build("UpdateExchangeEntryRequest"); + export interface ForceExchangeUpdateRequest { exchangeBaseUrl: string; } diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts index 6d66e7ad3..26e86f43f 100644 --- a/packages/taler-wallet-core/src/wallet-api-types.ts +++ b/packages/taler-wallet-core/src/wallet-api-types.ts @@ -110,6 +110,7 @@ import { TransactionsRequest, TransactionsResponse, TxIdResponse, + UpdateExchangeEntryRequest, UserAttentionByIdRequest, UserAttentionsCountResponse, UserAttentionsRequest, @@ -222,6 +223,7 @@ export enum WalletApiOperation { CreateStoredBackup = "createStoredBackup", DeleteStoredBackup = "deleteStoredBackup", RecoverStoredBackup = "recoverStoredBackup", + UpdateExchangeEntry = "updateExchangeEntry", } // group: Initialization @@ -557,6 +559,15 @@ export type AddExchangeOp = { response: EmptyObject; }; +/** + * Update an exchange entry. + */ +export type UpdateExchangeEntryOp = { + op: WalletApiOperation.UpdateExchangeEntry; + request: UpdateExchangeEntryRequest; + response: EmptyObject; +}; + export type ListKnownBankAccountsOp = { op: WalletApiOperation.ListKnownBankAccounts; request: ListKnownBankAccountsRequest; @@ -1125,6 +1136,7 @@ export type WalletOperations = { [WalletApiOperation.ListStoredBackups]: ListStoredBackupsOp; [WalletApiOperation.DeleteStoredBackup]: DeleteStoredBackupOp; [WalletApiOperation.RecoverStoredBackup]: RecoverStoredBackupsOp; + [WalletApiOperation.UpdateExchangeEntry]: UpdateExchangeEntryOp; }; export type WalletCoreRequestType< diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 496297021..44076667d 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -128,6 +128,7 @@ import { codecForTestingSetTimetravelRequest, setDangerousTimetravel, TestingWaitTransactionRequest, + codecForUpdateExchangeEntryRequest, } from "@gnu-taler/taler-util"; import type { HttpRequestLibrary } from "@gnu-taler/taler-util/http"; import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; @@ -1071,8 +1072,7 @@ async function dispatchRequestInternal( case WalletApiOperation.WithdrawTestkudos: { await withdrawTestBalance(ws, { amount: "TESTKUDOS:10", - bankAccessApiBaseUrl: - "https://bank.test.taler.net/", + bankAccessApiBaseUrl: "https://bank.test.taler.net/", exchangeBaseUrl: "https://exchange.test.taler.net/", }); return { @@ -1122,6 +1122,11 @@ async function dispatchRequestInternal( }); return {}; } + case WalletApiOperation.UpdateExchangeEntry: { + const req = codecForUpdateExchangeEntryRequest().decode(payload); + await updateExchangeFromUrl(ws, req.exchangeBaseUrl, {}); + return {}; + } case WalletApiOperation.ListExchanges: { return await getExchanges(ws); } -- cgit v1.2.3 From 8e70b89593a375bb19432e6521daed618ae779f5 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 2 Oct 2023 23:24:06 +0200 Subject: wallet-core: currency hint for preset exchanges --- packages/taler-wallet-core/src/db.ts | 6 ++++++ packages/taler-wallet-core/src/operations/common.ts | 2 +- packages/taler-wallet-core/src/operations/exchanges.ts | 4 +++- packages/taler-wallet-core/src/wallet-api-types.ts | 7 ++++++- packages/taler-wallet-core/src/wallet.ts | 18 ++++++++++++------ 5 files changed, 28 insertions(+), 9 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 156651cc6..d59085dcc 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -620,6 +620,12 @@ export interface ExchangeEntryRecord { */ baseUrl: string; + /** + * Currency hint for a preset exchange, relevant + * when we didn't contact a preset exchange yet. + */ + presetCurrencyHint?: string; + /** * When did we confirm the last withdrawal from this exchange? * diff --git a/packages/taler-wallet-core/src/operations/common.ts b/packages/taler-wallet-core/src/operations/common.ts index e8e492c08..b28a5363d 100644 --- a/packages/taler-wallet-core/src/operations/common.ts +++ b/packages/taler-wallet-core/src/operations/common.ts @@ -593,7 +593,7 @@ export function makeExchangeListItem( return { exchangeBaseUrl: r.baseUrl, - currency: exchangeDetails?.currency, + currency: exchangeDetails?.currency ?? r.presetCurrencyHint, exchangeUpdateStatus, exchangeEntryStatus, tosStatus: exchangeDetails diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts index 5e966b719..82d7b42bf 100644 --- a/packages/taler-wallet-core/src/operations/exchanges.ts +++ b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -309,6 +309,7 @@ export async function downloadExchangeInfo( export async function addPresetExchangeEntry( tx: WalletDbReadWriteTransaction<"exchanges">, exchangeBaseUrl: string, + currencyHint?: string, ): Promise { let exchange = await tx.exchanges.get(exchangeBaseUrl); if (!exchange) { @@ -316,6 +317,7 @@ export async function addPresetExchangeEntry( entryStatus: ExchangeEntryDbRecordStatus.Preset, updateStatus: ExchangeEntryDbUpdateStatus.Initial, baseUrl: exchangeBaseUrl, + presetCurrencyHint: currencyHint, detailsPointer: undefined, lastUpdate: undefined, lastKeysEtag: undefined, @@ -330,7 +332,7 @@ export async function addPresetExchangeEntry( } } -export async function provideExchangeRecordInTx( +async function provideExchangeRecordInTx( ws: InternalWalletState, tx: GetReadWriteAccess<{ exchanges: typeof WalletStoresV1.exchanges; diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts index 26e86f43f..375e0a1b2 100644 --- a/packages/taler-wallet-core/src/wallet-api-types.ts +++ b/packages/taler-wallet-core/src/wallet-api-types.ts @@ -254,6 +254,11 @@ export type GetVersionOp = { */ export type WalletConfigParameter = RecursivePartial; +export interface BuiltinExchange { + exchangeBaseUrl: string; + currencyHint?: string; +} + export interface WalletConfig { /** * Initialization values useful for a complete startup. @@ -261,7 +266,7 @@ export interface WalletConfig { * These are values may be overridden by different wallets */ builtin: { - exchanges: string[]; + exchanges: BuiltinExchange[]; }; /** diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 44076667d..203adec0f 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -200,7 +200,6 @@ import { downloadTosFromAcceptedFormat, getExchangeDetails, getExchangeRequestTimeout, - provideExchangeRecordInTx, updateExchangeFromUrl, updateExchangeFromUrlHandler, } from "./operations/exchanges.js"; @@ -535,10 +534,12 @@ async function fillDefaults(ws: InternalWalletState): Promise { logger.trace("defaults already applied"); return; } - for (const baseUrl of ws.config.builtin.exchanges) { - await addPresetExchangeEntry(tx, baseUrl); - const now = AbsoluteTime.now(); - provideExchangeRecordInTx(ws, tx, baseUrl, now); + for (const exch of ws.config.builtin.exchanges) { + await addPresetExchangeEntry( + tx, + exch.exchangeBaseUrl, + exch.currencyHint, + ); } await tx.config.put({ key: ConfigRecordKey.CurrencyDefaultsApplied, @@ -1672,7 +1673,12 @@ export class Wallet { public static defaultConfig: Readonly = { builtin: { - exchanges: ["https://exchange.demo.taler.net/"], + exchanges: [ + { + exchangeBaseUrl: "https://exchange.demo.taler.net/", + currencyHint: "KUDOS", + }, + ], }, features: { allowHttp: false, -- cgit v1.2.3 From 97d7be7503168f4f3bbd05905d32aa76ca1636b2 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 6 Oct 2023 14:42:32 +0200 Subject: rename to corebank API --- packages/taler-harness/src/bench1.ts | 2 +- packages/taler-harness/src/bench3.ts | 2 +- packages/taler-harness/src/harness/harness.ts | 10 +++++----- packages/taler-harness/src/harness/helpers.ts | 2 +- packages/taler-harness/src/index.ts | 6 +++--- .../src/integrationtests/test-age-restrictions-merchant.ts | 2 +- .../taler-harness/src/integrationtests/test-bank-api.ts | 2 +- .../src/integrationtests/test-exchange-deposit.ts | 2 +- .../src/integrationtests/test-exchange-management.ts | 2 +- .../src/integrationtests/test-exchange-purse.ts | 2 +- .../src/integrationtests/test-forced-selection.ts | 2 +- packages/taler-harness/src/integrationtests/test-kyc.ts | 2 +- .../src/integrationtests/test-libeufin-bank.ts | 2 +- .../src/integrationtests/test-payment-fault.ts | 2 +- .../taler-harness/src/integrationtests/test-tipping.ts | 2 +- .../src/integrationtests/test-wallet-dbless.ts | 2 +- .../src/integrationtests/test-wallet-notifications.ts | 2 +- .../src/integrationtests/test-wallettesting.ts | 6 +++--- .../src/integrationtests/test-withdrawal-abort-bank.ts | 2 +- .../integrationtests/test-withdrawal-bank-integrated.ts | 2 +- .../src/integrationtests/test-withdrawal-fakebank.ts | 2 +- .../src/integrationtests/test-withdrawal-fees.ts | 2 +- .../src/integrationtests/test-withdrawal-huge.ts | 2 +- .../src/integrationtests/test-withdrawal-manual.ts | 2 +- packages/taler-util/src/wallet-types.ts | 14 +++++++------- packages/taler-wallet-cli/src/index.ts | 4 ++-- packages/taler-wallet-core/src/dbless.ts | 6 +++--- packages/taler-wallet-core/src/operations/testing.ts | 14 +++++++------- packages/taler-wallet-core/src/wallet.ts | 2 +- packages/taler-wallet-embedded/src/wallet-qjs.ts | 4 ++-- 30 files changed, 54 insertions(+), 54 deletions(-) (limited to 'packages/taler-wallet-core') diff --git a/packages/taler-harness/src/bench1.ts b/packages/taler-harness/src/bench1.ts index f7b42836d..efe162320 100644 --- a/packages/taler-harness/src/bench1.ts +++ b/packages/taler-harness/src/bench1.ts @@ -98,7 +98,7 @@ export async function runBench1(configJson: any): Promise { await wallet.client.call(WalletApiOperation.WithdrawTestBalance, { amount: b1conf.currency + ":" + withdrawAmount, - bankAccessApiBaseUrl: b1conf.bank, + corebankApiBaseUrl: b1conf.bank, exchangeBaseUrl: b1conf.exchange, }); diff --git a/packages/taler-harness/src/bench3.ts b/packages/taler-harness/src/bench3.ts index 55cd335f2..bc345aa9e 100644 --- a/packages/taler-harness/src/bench3.ts +++ b/packages/taler-harness/src/bench3.ts @@ -109,7 +109,7 @@ export async function runBench3(configJson: any): Promise { await wallet.client.call(WalletApiOperation.WithdrawTestBalance, { amount: b3conf.currency + ":" + withdrawAmount, - bankAccessApiBaseUrl: b3conf.bank, + corebankApiBaseUrl: b3conf.bank, exchangeBaseUrl: b3conf.exchange, }); diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts index a57cb4355..e30cbcb54 100644 --- a/packages/taler-harness/src/harness/harness.ts +++ b/packages/taler-harness/src/harness/harness.ts @@ -650,7 +650,7 @@ export class FakebankService return `http://localhost:${this.bankConfig.httpPort}/`; } - get bankAccessApiBaseUrl(): string { + get corebankApiBaseUrl(): string { return this.baseUrl; } @@ -691,7 +691,7 @@ export class FakebankService "bank", ); await this.pingUntilAvailable(); - const bankClient = new TalerCorebankApiClient(this.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(this.corebankApiBaseUrl); for (const acc of this.accounts) { await bankClient.registerAccount(acc.accountName, acc.accountPassword); } @@ -798,7 +798,7 @@ export class LibeufinBankService return `http://localhost:${this.bankConfig.httpPort}/`; } - get bankAccessApiBaseUrl(): string { + get corebankApiBaseUrl(): string { return this.baseUrl; } @@ -825,7 +825,7 @@ export class LibeufinBankService "libeufin-bank-httpd", ); await this.pingUntilAvailable(); - const bankClient = new TalerCorebankApiClient(this.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(this.corebankApiBaseUrl); for (const acc of this.accounts) { await bankClient.registerAccount(acc.accountName, acc.accountPassword); } @@ -841,7 +841,7 @@ export class LibeufinBankService const useLibeufinBank = false; export interface BankServiceHandle { - readonly bankAccessApiBaseUrl: string; + readonly corebankApiBaseUrl: string; readonly http: HttpRequestLibrary; } diff --git a/packages/taler-harness/src/harness/helpers.ts b/packages/taler-harness/src/harness/helpers.ts index 68b7d087c..8c1612457 100644 --- a/packages/taler-harness/src/harness/helpers.ts +++ b/packages/taler-harness/src/harness/helpers.ts @@ -560,7 +560,7 @@ export async function withdrawViaBankV2( ): Promise { const { walletClient: wallet, bank, exchange, amount } = p; - const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.corebankApiBaseUrl); const user = await bankClient.createRandomBankUser(); const wop = await bankClient.createWithdrawalOperation(user.username, amount); diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts index 1f5156b57..82d8e4326 100644 --- a/packages/taler-harness/src/index.ts +++ b/packages/taler-harness/src/index.ts @@ -312,7 +312,7 @@ deploymentCli const exchangeInfo = await downloadExchangeInfo(exchangeBaseUrl, http); await topupReserveWithDemobank({ amount: "KUDOS:10", - bankAccessApiBaseUrl: + corebankApiBaseUrl: "https://bank.demo.taler.net/", exchangeInfo, http, @@ -341,7 +341,7 @@ deploymentCli const exchangeInfo = await downloadExchangeInfo(exchangeBaseUrl, http); await topupReserveWithDemobank({ amount: "TESTKUDOS:10", - bankAccessApiBaseUrl: + corebankApiBaseUrl: "https://bank.test.taler.net/", exchangeInfo, http, @@ -371,7 +371,7 @@ deploymentCli const exchangeInfo = await downloadExchangeInfo(exchangeBaseUrl, http); await topupReserveWithDemobank({ amount: "TESTKUDOS:10", - bankAccessApiBaseUrl: "http://localhost:8082/taler-bank-access/", + corebankApiBaseUrl: "http://localhost:8082/taler-bank-access/", exchangeInfo, http, reservePub: reserveKeyPair.pub, diff --git a/packages/taler-harness/src/integrationtests/test-age-restrictions-merchant.ts b/packages/taler-harness/src/integrationtests/test-age-restrictions-merchant.ts index 90b08724f..5653e22e2 100644 --- a/packages/taler-harness/src/integrationtests/test-age-restrictions-merchant.ts +++ b/packages/taler-harness/src/integrationtests/test-age-restrictions-merchant.ts @@ -179,7 +179,7 @@ export async function runAgeRestrictionsMerchantTest(t: GlobalTestState) { // Pay with coin from tipping { - const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.corebankApiBaseUrl); const mbu = await bankClient.createRandomBankUser(); const tipReserveResp = await merchantClient.createTippingReserve({ exchange_url: exchange.baseUrl, diff --git a/packages/taler-harness/src/integrationtests/test-bank-api.ts b/packages/taler-harness/src/integrationtests/test-bank-api.ts index b87a4043b..9c5b06397 100644 --- a/packages/taler-harness/src/integrationtests/test-bank-api.ts +++ b/packages/taler-harness/src/integrationtests/test-bank-api.ts @@ -99,7 +99,7 @@ export async function runBankApiTest(t: GlobalTestState) { console.log("setup done!"); - const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.corebankApiBaseUrl); const bankUser = await bankClient.registerAccount("user1", "pw1"); diff --git a/packages/taler-harness/src/integrationtests/test-exchange-deposit.ts b/packages/taler-harness/src/integrationtests/test-exchange-deposit.ts index 96255f5b5..8ad7daa63 100644 --- a/packages/taler-harness/src/integrationtests/test-exchange-deposit.ts +++ b/packages/taler-harness/src/integrationtests/test-exchange-deposit.ts @@ -66,7 +66,7 @@ export async function runExchangeDepositTest(t: GlobalTestState) { await topupReserveWithDemobank({ http, amount: "TESTKUDOS:10", - bankAccessApiBaseUrl: bank.bankAccessApiBaseUrl, + corebankApiBaseUrl: bank.corebankApiBaseUrl, exchangeInfo, reservePub: reserveKeyPair.pub, }); diff --git a/packages/taler-harness/src/integrationtests/test-exchange-management.ts b/packages/taler-harness/src/integrationtests/test-exchange-management.ts index fbee50385..a7908264d 100644 --- a/packages/taler-harness/src/integrationtests/test-exchange-management.ts +++ b/packages/taler-harness/src/integrationtests/test-exchange-management.ts @@ -263,7 +263,7 @@ export async function runExchangeManagementTest( // Create withdrawal operation - const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.corebankApiBaseUrl); const user = await bankClient.createRandomBankUser(); const wop = await bankClient.createWithdrawalOperation( diff --git a/packages/taler-harness/src/integrationtests/test-exchange-purse.ts b/packages/taler-harness/src/integrationtests/test-exchange-purse.ts index 5a1d02692..33a09ed16 100644 --- a/packages/taler-harness/src/integrationtests/test-exchange-purse.ts +++ b/packages/taler-harness/src/integrationtests/test-exchange-purse.ts @@ -79,7 +79,7 @@ export async function runExchangePurseTest(t: GlobalTestState) { amount: "TESTKUDOS:10", http, reservePub: reserveKeyPair.pub, - bankAccessApiBaseUrl: bank.bankAccessApiBaseUrl, + corebankApiBaseUrl: bank.corebankApiBaseUrl, exchangeInfo, }); diff --git a/packages/taler-harness/src/integrationtests/test-forced-selection.ts b/packages/taler-harness/src/integrationtests/test-forced-selection.ts index 3425dadf1..917ad2025 100644 --- a/packages/taler-harness/src/integrationtests/test-forced-selection.ts +++ b/packages/taler-harness/src/integrationtests/test-forced-selection.ts @@ -38,7 +38,7 @@ export async function runForcedSelectionTest(t: GlobalTestState) { await walletClient.call(WalletApiOperation.WithdrawTestBalance, { exchangeBaseUrl: exchange.baseUrl, amount: "TESTKUDOS:10", - bankAccessApiBaseUrl: bank.bankAccessApiBaseUrl, + corebankApiBaseUrl: bank.corebankApiBaseUrl, forcedDenomSel: { denoms: [ { diff --git a/packages/taler-harness/src/integrationtests/test-kyc.ts b/packages/taler-harness/src/integrationtests/test-kyc.ts index d646995d6..319e8828f 100644 --- a/packages/taler-harness/src/integrationtests/test-kyc.ts +++ b/packages/taler-harness/src/integrationtests/test-kyc.ts @@ -302,7 +302,7 @@ export async function runKycTest(t: GlobalTestState) { // Withdraw digital cash into the wallet. - const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.corebankApiBaseUrl); const amount = "TESTKUDOS:20"; const user = await bankClient.createRandomBankUser(); diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-bank.ts b/packages/taler-harness/src/integrationtests/test-libeufin-bank.ts index 66b4c0b80..c8c668bed 100644 --- a/packages/taler-harness/src/integrationtests/test-libeufin-bank.ts +++ b/packages/taler-harness/src/integrationtests/test-libeufin-bank.ts @@ -126,7 +126,7 @@ export async function runLibeufinBankTest(t: GlobalTestState) { console.log("setup done!"); - const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.corebankApiBaseUrl); // register exchange bank account await bankClient.registerAccountExtended({ diff --git a/packages/taler-harness/src/integrationtests/test-payment-fault.ts b/packages/taler-harness/src/integrationtests/test-payment-fault.ts index 63244a4e3..af6751ef4 100644 --- a/packages/taler-harness/src/integrationtests/test-payment-fault.ts +++ b/packages/taler-harness/src/integrationtests/test-payment-fault.ts @@ -127,7 +127,7 @@ export async function runPaymentFaultTest(t: GlobalTestState) { // Create withdrawal operation - const bankClient = new TalerCorebankApiClient(bank.bankAccessApiBaseUrl); + const bankClient = new TalerCorebankApiClient(bank.corebankApiBaseUrl); const user = await bankClient.createRandomBankUser(); const wop = await bankClient.createWithdrawalOperation( diff --git a/packages/taler-harness/src/integrationtests/test-tipping.ts b/packages/taler-harness/src/integrationtests/test-tipping.ts index 3d4ea6663..12cdbae53 100644 --- a/packages/taler-harness/src/integrationtests/test-tipping.ts +++ b/packages/taler-harness/src/integrationtests/test-tipping.ts @@ -39,7 +39,7 @@ export async function runTippingTest(t: GlobalTestState) { await createSimpleTestkudosEnvironmentV2(t); const bankAccessApiClient = new TalerCorebankApiClient( - bank.bankAccessApiBaseUrl, + bank.corebankApiBaseUrl, ); const mbu = await bankAccessApiClient.createRandomBankUser(); diff --git a/packages/taler-harness/src/integrationtests/test-wallet-dbless.ts b/packages/taler-harness/src/integrationtests/test-wallet-dbless.ts index 153ae93d8..5e6539654 100644 --- a/packages/taler-harness/src/integrationtests/test-wallet-dbless.ts +++ b/packages/taler-harness/src/integrationtests/test-wallet-dbless.ts @@ -72,7 +72,7 @@ export async function runWalletDblessTest(t: GlobalTestState) { amount: "TESTKUDOS:10", http, reservePub: reserveKeyPair.pub, - bankAccessApiBaseUrl: bank.bankAccessApiBaseUrl, + corebankApiBaseUrl: bank.corebankApiBaseUrl, exchangeInfo, }); diff --git a/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts b/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts index 0b5bc45ef..c87a9a264 100644 --- a/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts +++ b/packages/taler-harness/src/integrationtests/test-wallet-notifications.ts @@ -122,7 +122,7 @@ export async function runWalletNotificationsTest(t: GlobalTestState) { }); const bankAccessApiClient = new TalerCorebankApiClient( - bank.bankAccessApiBaseUrl, + bank.corebankApiBaseUrl, ); const user = await bankAccessApiClient.createRandomBankUser(); bankAccessApiClient.setAuth(user); diff --git a/packages/taler-harness/src/integrationtests/test-wallettesting.ts b/packages/taler-harness/src/integrationtests/test-wallettesting.ts index 6d58ae1f2..e5191aa5b 100644 --- a/packages/taler-harness/src/integrationtests/test-wallettesting.ts +++ b/packages/taler-harness/src/integrationtests/test-wallettesting.ts @@ -120,7 +120,7 @@ export async function runWallettestingTest(t: GlobalTestState) { await wallet.client.call(WalletApiOperation.RunIntegrationTest, { amountToSpend: "TESTKUDOS:5", amountToWithdraw: "TESTKUDOS:10", - bankAccessApiBaseUrl: bank.bankAccessApiBaseUrl, + corebankApiBaseUrl: bank.corebankApiBaseUrl, exchangeBaseUrl: exchange.baseUrl, merchantAuthToken: merchantAuthToken, merchantBaseUrl: merchant.makeInstanceBaseUrl(), @@ -143,7 +143,7 @@ export async function runWallettestingTest(t: GlobalTestState) { await wallet.client.call(WalletApiOperation.WithdrawTestBalance, { amount: "TESTKUDOS:10", - bankAccessApiBaseUrl: bank.bankAccessApiBaseUrl, + corebankApiBaseUrl: bank.corebankApiBaseUrl, exchangeBaseUrl: exchange.baseUrl, }); @@ -168,7 +168,7 @@ export async function runWallettestingTest(t: GlobalTestState) { await wallet.client.call(WalletApiOperation.WithdrawTestBalance, { amount: "TESTKUDOS:10", - bankAccessApiBaseUrl: bank.bankAccessApiBaseUrl, + corebankApiBaseUrl: bank.corebankApiBaseUrl, exchangeBaseUrl: exchange.baseUrl, }); diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-abort-bank.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-abort-bank.ts index 4a0dd845b..f9f2df0fc 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-abort-bank.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-abort-bank.ts @@ -34,7 +34,7 @@ export async function runWithdrawalAbortBankTest(t: GlobalTestState) { // Create a withdrawal operation const bankAccessApiClient = new TalerCorebankApiClient( - bank.bankAccessApiBaseUrl, + bank.corebankApiBaseUrl, ); const user = await bankAccessApiClient.createRandomBankUser(); bankAccessApiClient.setAuth(user); diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts index 817da5865..76dec50d3 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-bank-integrated.ts @@ -42,7 +42,7 @@ export async function runWithdrawalBankIntegratedTest(t: GlobalTestState) { // Create a withdrawal operation const corebankApiClient = new TalerCorebankApiClient( - bank.bankAccessApiBaseUrl, + bank.corebankApiBaseUrl, ); const user = await corebankApiClient.createRandomBankUser(); corebankApiClient.setAuth(user); diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-fakebank.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-fakebank.ts index 84b7b37bf..e3057451e 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-fakebank.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-fakebank.ts @@ -80,7 +80,7 @@ export async function runWithdrawalFakebankTest(t: GlobalTestState) { }); await wallet.client.call(WalletApiOperation.WithdrawTestBalance, { - bankAccessApiBaseUrl: bank.bankAccessApiBaseUrl, + corebankApiBaseUrl: bank.corebankApiBaseUrl, exchangeBaseUrl: exchange.baseUrl, amount: "TESTKUDOS:10", }); diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-fees.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-fees.ts index d3df19664..f702376e1 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-fees.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-fees.ts @@ -108,7 +108,7 @@ export async function runWithdrawalFeesTest(t: GlobalTestState) { const amount = "TESTKUDOS:7.5"; const bankAccessApiClient = new TalerCorebankApiClient( - bank.bankAccessApiBaseUrl, + bank.corebankApiBaseUrl, ); const user = await bankAccessApiClient.createRandomBankUser(); bankAccessApiClient.setAuth(user); diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-huge.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-huge.ts index 0dfc77447..893d870e5 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-huge.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-huge.ts @@ -102,7 +102,7 @@ export async function runWithdrawalHugeTest(t: GlobalTestState) { await wallet.client.call(WalletApiOperation.WithdrawTestBalance, { exchangeBaseUrl: exchange.baseUrl, amount: "TESTKUDOS:10000", - bankAccessApiBaseUrl: bank.baseUrl, + corebankApiBaseUrl: bank.baseUrl, }); await withdrawalFinishedCond; diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-manual.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-manual.ts index 316e3cc18..fa483aa28 100644 --- a/packages/taler-harness/src/integrationtests/test-withdrawal-manual.ts +++ b/packages/taler-harness/src/integrationtests/test-withdrawal-manual.ts @@ -42,7 +42,7 @@ export async function runWithdrawalManualTest(t: GlobalTestState) { // Create a withdrawal operation const bankAccessApiClient = new TalerCorebankApiClient( - bank.bankAccessApiBaseUrl, + bank.corebankApiBaseUrl, ); const user = await bankAccessApiClient.createRandomBankUser(); diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts index 8fff8ae55..4811d674f 100644 --- a/packages/taler-util/src/wallet-types.ts +++ b/packages/taler-util/src/wallet-types.ts @@ -1556,7 +1556,7 @@ export const codecForTestPayArgs = (): Codec => export interface IntegrationTestArgs { exchangeBaseUrl: string; - bankAccessApiBaseUrl: string; + corebankApiBaseUrl: string; merchantBaseUrl: string; merchantAuthToken?: string; amountToWithdraw: string; @@ -1570,12 +1570,12 @@ export const codecForIntegrationTestArgs = (): Codec => .property("merchantAuthToken", codecOptional(codecForString())) .property("amountToSpend", codecForAmountString()) .property("amountToWithdraw", codecForAmountString()) - .property("bankAccessApiBaseUrl", codecForAmountString()) + .property("corebankApiBaseUrl", codecForAmountString()) .build("IntegrationTestArgs"); export interface IntegrationTestV2Args { exchangeBaseUrl: string; - bankAccessApiBaseUrl: string; + corebankApiBaseUrl: string; merchantBaseUrl: string; merchantAuthToken?: string; } @@ -1585,7 +1585,7 @@ export const codecForIntegrationTestV2Args = (): Codec => .property("exchangeBaseUrl", codecForString()) .property("merchantBaseUrl", codecForString()) .property("merchantAuthToken", codecOptional(codecForString())) - .property("bankAccessApiBaseUrl", codecForAmountString()) + .property("corebankApiBaseUrl", codecForAmountString()) .build("IntegrationTestV2Args"); export interface AddExchangeRequest { @@ -1861,9 +1861,9 @@ export interface CoreApiResponseError { export interface WithdrawTestBalanceRequest { amount: string; /** - * Bank access API base URL. + * Corebank API base URL. */ - bankAccessApiBaseUrl: string; + corebankApiBaseUrl: string; exchangeBaseUrl: string; forcedDenomSel?: ForcedDenomSel; } @@ -1936,7 +1936,7 @@ export const codecForWithdrawTestBalance = .property("amount", codecForString()) .property("exchangeBaseUrl", codecForString()) .property("forcedDenomSel", codecForAny()) - .property("bankAccessApiBaseUrl", codecForString()) + .property("corebankApiBaseUrl", codecForString()) .build("WithdrawTestBalanceRequest"); export interface SetCoinSuspendedRequest { diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index bfc259481..f3b205211 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -1280,7 +1280,7 @@ advancedCli await wallet.client.call(WalletApiOperation.RunIntegrationTest, { amountToSpend: "TESTKUDOS:1", amountToWithdraw: "TESTKUDOS:3", - bankAccessApiBaseUrl: "http://localhost:8082/taler-bank-access/", + corebankApiBaseUrl: "http://localhost:8082/taler-bank-access/", exchangeBaseUrl: "http://localhost:8081/", merchantBaseUrl: "http://localhost:8083/", }); @@ -1507,7 +1507,7 @@ testCli.subcommand("withdrawKudos", "withdraw-kudos").action(async (args) => { await withWallet(args, async (wallet) => { await wallet.client.call(WalletApiOperation.WithdrawTestBalance, { amount: "KUDOS:50", - bankAccessApiBaseUrl: + corebankApiBaseUrl: "https://bank.demo.taler.net/", exchangeBaseUrl: "https://exchange.demo.taler.net/", }); diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts index 0d702a00c..4fc890788 100644 --- a/packages/taler-wallet-core/src/dbless.ts +++ b/packages/taler-wallet-core/src/dbless.ts @@ -109,7 +109,7 @@ export async function checkReserve( export interface TopupReserveWithDemobankArgs { http: HttpRequestLibrary; reservePub: string; - bankAccessApiBaseUrl: string; + corebankApiBaseUrl: string; exchangeInfo: ExchangeInfo; amount: AmountString; } @@ -117,8 +117,8 @@ export interface TopupReserveWithDemobankArgs { export async function topupReserveWithDemobank( args: TopupReserveWithDemobankArgs, ) { - const { http, bankAccessApiBaseUrl, amount, exchangeInfo, reservePub } = args; - const bankClient = new TalerCorebankApiClient(bankAccessApiBaseUrl); + const { http, corebankApiBaseUrl, amount, exchangeInfo, reservePub } = args; + const bankClient = new TalerCorebankApiClient(corebankApiBaseUrl); const bankUser = await bankClient.createRandomBankUser(); const wopi = await bankClient.createWithdrawalOperation( bankUser.username, diff --git a/packages/taler-wallet-core/src/operations/testing.ts b/packages/taler-wallet-core/src/operations/testing.ts index b21f1992c..607d03470 100644 --- a/packages/taler-wallet-core/src/operations/testing.ts +++ b/packages/taler-wallet-core/src/operations/testing.ts @@ -102,13 +102,13 @@ export async function withdrawTestBalance( ): Promise { const amount = req.amount; const exchangeBaseUrl = req.exchangeBaseUrl; - const bankAccessApiBaseUrl = req.bankAccessApiBaseUrl; + const corebankApiBaseUrl = req.corebankApiBaseUrl; logger.trace( - `Registering bank user, bank access base url ${bankAccessApiBaseUrl}`, + `Registering bank user, bank access base url ${corebankApiBaseUrl}`, ); - const corebankClient = new TalerCorebankApiClient(bankAccessApiBaseUrl); + const corebankClient = new TalerCorebankApiClient(corebankApiBaseUrl); const bankUser = await corebankClient.createRandomBankUser(); logger.trace(`Registered bank user ${JSON.stringify(bankUser)}`); @@ -287,7 +287,7 @@ export async function runIntegrationTest( logger.info("withdrawing test balance"); await withdrawTestBalance(ws, { amount: args.amountToWithdraw, - bankAccessApiBaseUrl: args.bankAccessApiBaseUrl, + corebankApiBaseUrl: args.corebankApiBaseUrl, exchangeBaseUrl: args.exchangeBaseUrl, }); await waitUntilDone(ws); @@ -315,7 +315,7 @@ export async function runIntegrationTest( await withdrawTestBalance(ws, { amount: Amounts.stringify(withdrawAmountTwo), - bankAccessApiBaseUrl: args.bankAccessApiBaseUrl, + corebankApiBaseUrl: args.corebankApiBaseUrl, exchangeBaseUrl: args.exchangeBaseUrl, }); @@ -557,7 +557,7 @@ export async function runIntegrationTest2( logger.info("withdrawing test balance"); await withdrawTestBalance(ws, { amount: Amounts.stringify(amountToWithdraw), - bankAccessApiBaseUrl: args.bankAccessApiBaseUrl, + corebankApiBaseUrl: args.corebankApiBaseUrl, exchangeBaseUrl: args.exchangeBaseUrl, }); await waitUntilDone(ws); @@ -590,7 +590,7 @@ export async function runIntegrationTest2( await withdrawTestBalance(ws, { amount: Amounts.stringify(withdrawAmountTwo), - bankAccessApiBaseUrl: args.bankAccessApiBaseUrl, + corebankApiBaseUrl: args.corebankApiBaseUrl, exchangeBaseUrl: args.exchangeBaseUrl, }); diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 203adec0f..ead0ee407 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -1073,7 +1073,7 @@ async function dispatchRequestInternal( case WalletApiOperation.WithdrawTestkudos: { await withdrawTestBalance(ws, { amount: "TESTKUDOS:10", - bankAccessApiBaseUrl: "https://bank.test.taler.net/", + corebankApiBaseUrl: "https://bank.test.taler.net/", exchangeBaseUrl: "https://exchange.test.taler.net/", }); return { diff --git a/packages/taler-wallet-embedded/src/wallet-qjs.ts b/packages/taler-wallet-embedded/src/wallet-qjs.ts index e0888aa8a..1b3e3ae81 100644 --- a/packages/taler-wallet-embedded/src/wallet-qjs.ts +++ b/packages/taler-wallet-embedded/src/wallet-qjs.ts @@ -278,7 +278,7 @@ export async function testWithGv() { await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, { amountToSpend: "KUDOS:1", amountToWithdraw: "KUDOS:3", - bankAccessApiBaseUrl: + corebankApiBaseUrl: "https://bank.demo.taler.net/", exchangeBaseUrl: "https://exchange.demo.taler.net/", merchantBaseUrl: "https://backend.demo.taler.net/", @@ -306,7 +306,7 @@ export async function testWithLocal(path: string) { await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, { amountToSpend: "TESTKUDOS:1", amountToWithdraw: "TESTKUDOS:3", - bankAccessApiBaseUrl: "http://localhost:8082/taler-bank-access/", + corebankApiBaseUrl: "http://localhost:8082/taler-bank-access/", exchangeBaseUrl: "http://localhost:8081/", merchantBaseUrl: "http://localhost:8083/", }); -- cgit v1.2.3