summaryrefslogtreecommitdiff
path: root/packages/taler-util/src/http-client/bank-core.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-util/src/http-client/bank-core.ts')
-rw-r--r--packages/taler-util/src/http-client/bank-core.ts950
1 files changed, 650 insertions, 300 deletions
diff --git a/packages/taler-util/src/http-client/bank-core.ts b/packages/taler-util/src/http-client/bank-core.ts
index 51d6d7c96..6c8051ada 100644
--- a/packages/taler-util/src/http-client/bank-core.ts
+++ b/packages/taler-util/src/http-client/bank-core.ts
@@ -1,6 +1,6 @@
/*
This file is part of GNU Taler
- (C) 2022 Taler Systems S.A.
+ (C) 2022-2024 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
@@ -15,62 +15,126 @@
*/
import {
+ AbsoluteTime,
HttpStatusCode,
LibtoolVersion,
+ LongPollParams,
+ OperationAlternative,
+ OperationFail,
+ OperationOk,
TalerErrorCode,
- codecForTalerErrorDetail
+ codecForChallenge,
+ codecForTanTransmission,
+ opKnownAlternativeFailure,
+ opKnownHttpFailure,
+ opKnownTalerFailure,
} from "@gnu-taler/taler-util";
import {
HttpRequestLibrary,
- createPlatformHttpLib
+ createPlatformHttpLib,
+ readTalerErrorResponse,
} from "@gnu-taler/taler-util/http";
-import { FailCasesByMethod, ResultByMethod, opEmptySuccess, opFixedSuccess, opKnownFailure, opSuccess, opUnknownFailure } from "../operation.js";
-import { TalerAuthenticationHttpClient } from "./authentication.js";
-import { TalerBankConversionHttpClient } from "./bank-conversion.js";
-import { TalerBankIntegrationHttpClient } from "./bank-integration.js";
-import { TalerRevenueHttpClient } from "./bank-revenue.js";
-import { TalerWireGatewayHttpClient } from "./bank-wire.js";
-import { AccessToken, PaginationParams, TalerCorebankApi, UserAndToken, WithdrawalOperationStatus, codecForAccountData, codecForBankAccountCreateWithdrawalResponse, codecForBankAccountTransactionInfo, codecForBankAccountTransactionsResponse, codecForCashoutPending, codecForCashoutStatusResponse, codecForCashouts, codecForCoreBankConfig, codecForCreateTransactionResponse, codecForGlobalCashouts, codecForListBankAccountsResponse, codecForMonitorResponse, codecForPublicAccountsResponse, codecForRegisterAccountResponse, codecForWithdrawalPublicInfo } from "./types.js";
-import { addPaginationParams, makeBearerTokenAuthHeader } from "./utils.js";
-
+import {
+ FailCasesByMethod,
+ ResultByMethod,
+ opEmptySuccess,
+ opFixedSuccess,
+ opSuccessFromHttp,
+ opUnknownFailure,
+} from "../operation.js";
+import {
+ AccessToken,
+ PaginationParams,
+ TalerCorebankApi,
+ UserAndToken,
+ WithdrawalOperationStatus,
+ codecForAccountData,
+ codecForBankAccountCreateWithdrawalResponse,
+ codecForBankAccountTransactionInfo,
+ codecForBankAccountTransactionsResponse,
+ codecForCashoutPending,
+ codecForCashoutStatusResponse,
+ codecForCashouts,
+ codecForCoreBankConfig,
+ codecForCreateTransactionResponse,
+ codecForGlobalCashouts,
+ codecForListBankAccountsResponse,
+ codecForMonitorResponse,
+ codecForPublicAccountsResponse,
+ codecForRegisterAccountResponse,
+ codecForWithdrawalPublicInfo,
+} from "./types.js";
+import {
+ CacheEvictor,
+ IdempotencyRetry,
+ addLongPollingParam,
+ addPaginationParams,
+ makeBearerTokenAuthHeader,
+ nullEvictor,
+} from "./utils.js";
-export type TalerCoreBankResultByMethod<prop extends keyof TalerCoreBankHttpClient> = ResultByMethod<TalerCoreBankHttpClient, prop>
-export type TalerCoreBankErrorsByMethod<prop extends keyof TalerCoreBankHttpClient> = FailCasesByMethod<TalerCoreBankHttpClient, prop>
+export type TalerCoreBankResultByMethod<
+ prop extends keyof TalerCoreBankHttpClient,
+> = ResultByMethod<TalerCoreBankHttpClient, prop>;
+export type TalerCoreBankErrorsByMethod<
+ prop extends keyof TalerCoreBankHttpClient,
+> = FailCasesByMethod<TalerCoreBankHttpClient, prop>;
+export enum TalerCoreBankCacheEviction {
+ DELETE_ACCOUNT,
+ CREATE_ACCOUNT,
+ UPDATE_ACCOUNT,
+ UPDATE_PASSWORD,
+ CREATE_TRANSACTION,
+ CONFIRM_WITHDRAWAL,
+ ABORT_WITHDRAWAL,
+ CREATE_WITHDRAWAL,
+ CREATE_CASHOUT,
+}
/**
- * Protocol version spoken with the bank.
+ * Protocol version spoken with the core bank.
+ *
+ * Endpoint must be ordered in the same way that in the docs
+ * Response code (http and taler) must have the same order that in the docs
+ * That way is easier to see changes
*
* Uses libtool's current:revision:age versioning.
*/
export class TalerCoreBankHttpClient {
- public readonly PROTOCOL_VERSION = "0:0:0";
+ public readonly PROTOCOL_VERSION = "4:0:0";
httpLib: HttpRequestLibrary;
-
+ cacheEvictor: CacheEvictor<TalerCoreBankCacheEviction>;
constructor(
readonly baseUrl: string,
httpClient?: HttpRequestLibrary,
+ cacheEvictor?: CacheEvictor<TalerCoreBankCacheEviction>,
) {
this.httpLib = httpClient ?? createPlatformHttpLib();
+ this.cacheEvictor = cacheEvictor ?? nullEvictor;
}
isCompatible(version: string): boolean {
- const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version)
- return compare?.compatible ?? false
+ const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version);
+ return compare?.compatible ?? false;
}
/**
* https://docs.taler.net/core/api-corebank.html#config
- *
+ *
*/
async getConfig() {
const url = new URL(`config`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
- method: "GET"
+ method: "GET",
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForCoreBankConfig())
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForCoreBankConfig());
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
@@ -80,189 +144,287 @@ export class TalerCoreBankHttpClient {
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts
- *
+ *
*/
- async createAccount(auth: AccessToken, body: TalerCorebankApi.RegisterAccountRequest) {
+ async createAccount(
+ auth: AccessToken | undefined,
+ body: TalerCorebankApi.RegisterAccountRequest,
+ ) {
const url = new URL(`accounts`, this.baseUrl);
+ const headers: Record<string, string> = {};
+ if (auth) {
+ headers.Authorization = makeBearerTokenAuthHeader(auth);
+ }
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
body,
- headers: {
- Authorization: makeBearerTokenAuthHeader(auth)
- },
+ headers: headers,
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForRegisterAccountResponse())
- case HttpStatusCode.BadRequest: return opKnownFailure("invalid-phone-or-email", resp);
- case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp);
+ case HttpStatusCode.Ok: {
+ await this.cacheEvictor.notifySuccess(
+ TalerCoreBankCacheEviction.CREATE_ACCOUNT,
+ );
+ return opSuccessFromHttp(resp, codecForRegisterAccountResponse());
+ }
+ case HttpStatusCode.BadRequest:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
- const body = await resp.json()
- const details = codecForTalerErrorDetail().decode(body)
+ const details = await readTalerErrorResponse(resp);
switch (details.code) {
- case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE: return opKnownFailure("username-already-exists", resp);
- case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE: return opKnownFailure("payto-already-exists", resp);
- case TalerErrorCode.BANK_UNALLOWED_DEBIT: return opKnownFailure("insufficient-funds", resp);
- case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT: return opKnownFailure("username-reserved", resp);
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return opKnownFailure("user-cant-set-debt", resp);
- default: return opUnknownFailure(resp, body)
+ case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_UNALLOWED_DEBIT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_NON_ADMIN_SET_MIN_CASHOUT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_MISSING_TAN_INFO:
+ return opKnownTalerFailure(details.code, details);
+ default:
+ return opUnknownFailure(resp, details);
}
}
- default: return opUnknownFailure(resp, await resp.text())
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
* https://docs.taler.net/core/api-corebank.html#delete--accounts-$USERNAME
- *
+ *
*/
- async deleteAccount(auth: UserAndToken) {
+ async deleteAccount(auth: UserAndToken, cid?: string) {
const url = new URL(`accounts/${auth.username}`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "DELETE",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
+ "X-Challenge-Id": cid,
},
});
switch (resp.status) {
- case HttpStatusCode.NoContent: return opEmptySuccess()
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
- case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp);
+ case HttpStatusCode.Accepted:
+ return opKnownAlternativeFailure(
+ resp,
+ resp.status,
+ codecForChallenge(),
+ );
+ case HttpStatusCode.NoContent:
+ return opEmptySuccess(resp);
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
- const body = await resp.json()
- const details = codecForTalerErrorDetail().decode(body)
+ const details = await readTalerErrorResponse(resp);
switch (details.code) {
- case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT: return opKnownFailure("username-reserved", resp);
- case TalerErrorCode.BANK_ACCOUNT_BALANCE_NOT_ZERO: return opKnownFailure("balance-not-zero", resp);
- default: return opUnknownFailure(resp, body)
+ case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_ACCOUNT_BALANCE_NOT_ZERO:
+ return opKnownTalerFailure(details.code, details);
+ default:
+ return opUnknownFailure(resp, details);
}
}
- default: return opUnknownFailure(resp, await resp.text())
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
* https://docs.taler.net/core/api-corebank.html#patch--accounts-$USERNAME
- *
+ *
*/
- async updateAccount(auth: UserAndToken, body: TalerCorebankApi.AccountReconfiguration) {
+ async updateAccount(
+ auth: UserAndToken,
+ body: TalerCorebankApi.AccountReconfiguration,
+ cid?: string,
+ ) {
const url = new URL(`accounts/${auth.username}`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "PATCH",
body,
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
+ "X-Challenge-Id": cid,
},
});
switch (resp.status) {
- case HttpStatusCode.NoContent: return opEmptySuccess()
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
- case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp);
+ case HttpStatusCode.Accepted:
+ return opKnownAlternativeFailure(
+ resp,
+ resp.status,
+ codecForChallenge(),
+ );
+ case HttpStatusCode.NoContent:
+ return opEmptySuccess(resp);
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
- const body = await resp.json()
- const details = codecForTalerErrorDetail().decode(body)
+ const details = await readTalerErrorResponse(resp);
switch (details.code) {
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_NAME: return opKnownFailure("user-cant-change-name", resp);
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return opKnownFailure("user-cant-change-debt", resp);
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_CASHOUT: return opKnownFailure("user-cant-change-cashout", resp);
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_CONTACT: return opKnownFailure("user-cant-change-contact", resp);
- default: return opUnknownFailure(resp, body)
+ case TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_NAME:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_NON_ADMIN_PATCH_CASHOUT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_NON_ADMIN_SET_MIN_CASHOUT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_MISSING_TAN_INFO:
+ return opKnownTalerFailure(details.code, details);
+ default:
+ return opUnknownFailure(resp, details);
}
}
- default: return opUnknownFailure(resp, await resp.text())
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
* https://docs.taler.net/core/api-corebank.html#patch--accounts-$USERNAME-auth
- *
+ *
*/
- async updatePassword(auth: UserAndToken, body: TalerCorebankApi.AccountPasswordChange) {
+ async updatePassword(
+ auth: UserAndToken,
+ body: TalerCorebankApi.AccountPasswordChange,
+ cid?: string,
+ ) {
const url = new URL(`accounts/${auth.username}/auth`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "PATCH",
body,
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
+ "X-Challenge-Id": cid,
},
});
switch (resp.status) {
- case HttpStatusCode.NoContent: return opEmptySuccess()
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
- case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp);
+ case HttpStatusCode.Accepted:
+ return opKnownAlternativeFailure(
+ resp,
+ resp.status,
+ codecForChallenge(),
+ );
+ case HttpStatusCode.NoContent:
+ return opEmptySuccess(resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
- const body = await resp.json()
- const details = codecForTalerErrorDetail().decode(body)
+ const details = await readTalerErrorResponse(resp);
switch (details.code) {
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD: return opKnownFailure("user-require-old-password", resp);
- case TalerErrorCode.BANK_PATCH_BAD_OLD_PASSWORD: return opKnownFailure("wrong-old-password", resp);
- default: return opUnknownFailure(resp, body)
+ case TalerErrorCode.BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_PATCH_BAD_OLD_PASSWORD:
+ return opKnownTalerFailure(details.code, details);
+ default:
+ return opUnknownFailure(resp, details);
}
}
- default: return opUnknownFailure(resp, await resp.text())
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--public-accounts
- *
+ *
*/
- async getPublicAccounts(filter: { account?: string } = {}, pagination?: PaginationParams) {
+ async getPublicAccounts(
+ filter: { account?: string } = {},
+ pagination?: PaginationParams,
+ ) {
const url = new URL(`public-accounts`, this.baseUrl);
- addPaginationParams(url, pagination)
+ addPaginationParams(url, pagination);
if (filter.account !== undefined) {
- url.searchParams.set("filter_name", filter.account)
+ url.searchParams.set("filter_name", filter.account);
}
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForPublicAccountsResponse())
- case HttpStatusCode.NoContent: return opFixedSuccess({ public_accounts: [] })
- case HttpStatusCode.NotFound: return opFixedSuccess({ public_accounts: [] })
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForPublicAccountsResponse());
+ case HttpStatusCode.NoContent:
+ return opFixedSuccess({ public_accounts: [] });
+ case HttpStatusCode.NotFound:
+ return opFixedSuccess({ public_accounts: [] });
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--accounts
- *
+ *
*/
- async getAccounts(auth: AccessToken, filter: { account?: string } = {}, pagination?: PaginationParams) {
+ async getAccounts(
+ auth: AccessToken,
+ filter: { account?: string } = {},
+ pagination?: PaginationParams,
+ ) {
const url = new URL(`accounts`, this.baseUrl);
- addPaginationParams(url, pagination)
+ addPaginationParams(url, pagination);
if (filter.account !== undefined) {
- url.searchParams.set("filter_name", filter.account)
+ url.searchParams.set("filter_name", filter.account);
}
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth)
+ Authorization: makeBearerTokenAuthHeader(auth),
},
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForListBankAccountsResponse())
- case HttpStatusCode.NoContent: return opFixedSuccess({ accounts: [] })
- case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForListBankAccountsResponse());
+ case HttpStatusCode.NoContent:
+ return opFixedSuccess({ accounts: [] });
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME
- *
+ *
*/
async getAccount(auth: UserAndToken) {
const url = new URL(`accounts/${auth.username}`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
},
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForAccountData())
- case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp);
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForAccountData());
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
@@ -272,75 +434,137 @@ export class TalerCoreBankHttpClient {
/**
* https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-transactions
- *
+ *
*/
- async getTransactions(auth: UserAndToken, pagination?: PaginationParams) {
+ async getTransactions(
+ auth: UserAndToken,
+ params?: PaginationParams & LongPollParams,
+ ) {
const url = new URL(`accounts/${auth.username}/transactions`, this.baseUrl);
- addPaginationParams(url, pagination)
+ addPaginationParams(url, params);
+ addLongPollingParam(url, params);
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
},
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForBankAccountTransactionsResponse())
- case HttpStatusCode.NoContent: return opFixedSuccess({ transactions: [] })
- case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp);
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(
+ resp,
+ codecForBankAccountTransactionsResponse(),
+ );
+ case HttpStatusCode.NoContent:
+ return opFixedSuccess({ transactions: [] });
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-transactions-$TRANSACTION_ID
- *
+ *
*/
async getTransactionById(auth: UserAndToken, txid: number) {
- const url = new URL(`accounts/${auth.username}/transactions/${String(txid)}`, this.baseUrl);
+ const url = new URL(
+ `accounts/${auth.username}/transactions/${String(txid)}`,
+ this.baseUrl,
+ );
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
},
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForBankAccountTransactionInfo())
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
- case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForBankAccountTransactionInfo());
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-transactions
- *
+ *
*/
- async createTransaction(auth: UserAndToken, body: TalerCorebankApi.CreateTransactionRequest) {
+ async createTransaction(
+ auth: UserAndToken,
+ body: TalerCorebankApi.CreateTransactionRequest,
+ idempotencyCheck: IdempotencyRetry | undefined,
+ cid?: string,
+ ): Promise<
+ //manually definition all return types because of recursion
+ | OperationOk<TalerCorebankApi.CreateTransactionResponse>
+ | OperationAlternative<HttpStatusCode.Accepted, TalerCorebankApi.Challenge>
+ | OperationFail<HttpStatusCode.NotFound>
+ | OperationFail<HttpStatusCode.BadRequest>
+ | OperationFail<HttpStatusCode.Unauthorized>
+ | OperationFail<TalerErrorCode.BANK_UNALLOWED_DEBIT>
+ | OperationFail<TalerErrorCode.BANK_ADMIN_CREDITOR>
+ | OperationFail<TalerErrorCode.BANK_SAME_ACCOUNT>
+ | OperationFail<TalerErrorCode.BANK_UNKNOWN_CREDITOR>
+ | OperationFail<TalerErrorCode.BANK_TRANSFER_REQUEST_UID_REUSED>
+ > {
const url = new URL(`accounts/${auth.username}/transactions`, this.baseUrl);
+ if (idempotencyCheck) {
+ body.request_uid = idempotencyCheck.uid;
+ }
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
+ "X-Challenge-Id": cid,
},
body,
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForCreateTransactionResponse())
- case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", resp);
- case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp);
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForCreateTransactionResponse());
+ case HttpStatusCode.Accepted:
+ return opKnownAlternativeFailure(
+ resp,
+ resp.status,
+ codecForChallenge(),
+ );
+ case HttpStatusCode.BadRequest:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
- const body = await resp.json()
- const details = codecForTalerErrorDetail().decode(body)
+ const details = await readTalerErrorResponse(resp);
switch (details.code) {
- case TalerErrorCode.BANK_SAME_ACCOUNT: return opKnownFailure("creditor-same", resp);
- case TalerErrorCode.BANK_UNKNOWN_CREDITOR: return opKnownFailure("creditor-not-found", resp);
- case TalerErrorCode.BANK_UNALLOWED_DEBIT: return opKnownFailure("insufficient-funds", resp);
- default: return opUnknownFailure(resp, body)
+ case TalerErrorCode.BANK_ADMIN_CREDITOR:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_SAME_ACCOUNT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_UNKNOWN_CREDITOR:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_UNALLOWED_DEBIT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_TRANSFER_REQUEST_UID_REUSED:
+ if (!idempotencyCheck) {
+ return opKnownTalerFailure(details.code, details);
+ }
+ const nextRetry = idempotencyCheck.next();
+ return this.createTransaction(auth, body, nextRetry, cid);
+ default:
+ return opUnknownFailure(resp, details);
}
}
- default: return opUnknownFailure(resp, await resp.text())
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
@@ -350,101 +574,147 @@ export class TalerCoreBankHttpClient {
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals
- *
+ *
*/
- async createWithdrawal(auth: UserAndToken, body: TalerCorebankApi.BankAccountCreateWithdrawalRequest) {
+ async createWithdrawal(
+ auth: UserAndToken,
+ body: TalerCorebankApi.BankAccountCreateWithdrawalRequest,
+ ) {
const url = new URL(`accounts/${auth.username}/withdrawals`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
},
body,
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForBankAccountCreateWithdrawalResponse())
- case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", resp);
- case HttpStatusCode.Conflict: return opKnownFailure("insufficient-funds", resp);
- case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(
+ resp,
+ codecForBankAccountCreateWithdrawalResponse(),
+ );
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Conflict:
+ return opKnownHttpFailure(resp.status, resp);
+ //FIXME: missing in docs
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
- * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-abort
- *
+ * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-confirm
+ *
*/
- async abortWithdrawalById(auth: UserAndToken, wid: string) {
- const url = new URL(`accounts/${auth.username}/withdrawals/${wid}/abort`, this.baseUrl);
+ async confirmWithdrawalById(auth: UserAndToken, wid: string, cid?: string) {
+ const url = new URL(
+ `accounts/${auth.username}/withdrawals/${wid}/confirm`,
+ this.baseUrl,
+ );
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
+ "X-Challenge-Id": cid,
},
});
switch (resp.status) {
- case HttpStatusCode.NoContent: return opEmptySuccess()
+ case HttpStatusCode.Accepted:
+ return opKnownAlternativeFailure(
+ resp,
+ resp.status,
+ codecForChallenge(),
+ );
+ case HttpStatusCode.NoContent:
+ return opEmptySuccess(resp);
//FIXME: missing in docs
- case HttpStatusCode.BadRequest: return opKnownFailure("invalid-id", resp)
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
- case HttpStatusCode.Conflict: return opKnownFailure("previously-confirmed", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.BadRequest:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Conflict: {
+ const details = await readTalerErrorResponse(resp);
+ switch (details.code) {
+ case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_CONFIRM_INCOMPLETE:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_UNALLOWED_DEBIT:
+ return opKnownTalerFailure(details.code, details);
+ default:
+ return opUnknownFailure(resp, details);
+ }
+ }
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
- * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-confirm
- *
+ * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-abort
+ *
*/
- async confirmWithdrawalById(auth: UserAndToken, wid: string) {
- const url = new URL(`accounts/${auth.username}/withdrawals/${wid}/confirm`, this.baseUrl);
+ async abortWithdrawalById(auth: UserAndToken, wid: string) {
+ const url = new URL(
+ `accounts/${auth.username}/withdrawals/${wid}/abort`,
+ this.baseUrl,
+ );
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
},
});
switch (resp.status) {
- case HttpStatusCode.NoContent: return opEmptySuccess()
+ case HttpStatusCode.NoContent:
+ return opEmptySuccess(resp);
//FIXME: missing in docs
- case HttpStatusCode.BadRequest: return opKnownFailure("invalid-id", resp)
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
- case HttpStatusCode.Conflict: {
- const body = await resp.json()
- const details = codecForTalerErrorDetail().decode(body)
- switch (details.code) {
- case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT: return opKnownFailure("previously-aborted", resp);
- case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return opKnownFailure("no-exchange-or-reserve-selected", resp);
- case TalerErrorCode.BANK_UNALLOWED_DEBIT: return opKnownFailure("insufficient-funds", resp);
- default: return opUnknownFailure(resp, body)
- }
- }
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.BadRequest:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Conflict:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
* https://docs.taler.net/core/api-corebank.html#get--withdrawals-$WITHDRAWAL_ID
- *
+ *
*/
- async getWithdrawalById(wid: string, wait?: {
- old_state?: WithdrawalOperationStatus,
- timeoutMs: number
- }) {
+ async getWithdrawalById(
+ wid: string,
+ params?: {
+ old_state?: WithdrawalOperationStatus;
+ } & LongPollParams,
+ ) {
const url = new URL(`withdrawals/${wid}`, this.baseUrl);
- if (wait) {
- url.searchParams.set("long_poll_ms", String(wait.timeoutMs))
- url.searchParams.set("old_state", !wait.old_state ? "pending" : wait.old_state)
+ addLongPollingParam(url, params);
+ if (params) {
+ url.searchParams.set(
+ "old_state",
+ !params.old_state ? "pending" : params.old_state,
+ );
}
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForWithdrawalPublicInfo())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForWithdrawalPublicInfo());
//FIXME: missing in docs
- case HttpStatusCode.BadRequest: return opKnownFailure("invalid-id", resp)
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.BadRequest:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
@@ -454,153 +724,225 @@ export class TalerCoreBankHttpClient {
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts
- *
+ *
*/
- async createCashout(auth: UserAndToken, body: TalerCorebankApi.CashoutRequest) {
+ async createCashout(
+ auth: UserAndToken,
+ body: TalerCorebankApi.CashoutRequest,
+ cid?: string,
+ ) {
const url = new URL(`accounts/${auth.username}/cashouts`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
+ "X-Challenge-Id": cid,
},
body,
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForCashoutPending())
- case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", resp)
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForCashoutPending());
+ case HttpStatusCode.Accepted:
+ return opKnownAlternativeFailure(
+ resp,
+ resp.status,
+ codecForChallenge(),
+ );
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict: {
- const body = await resp.json()
- const details = codecForTalerErrorDetail().decode(body)
+ const details = await readTalerErrorResponse(resp);
switch (details.code) {
- case TalerErrorCode.BANK_TRANSFER_REQUEST_UID_REUSED: return opKnownFailure("request-already-used", resp);
- case TalerErrorCode.BANK_BAD_CONVERSION: return opKnownFailure("incorrect-exchange-rate", resp);
- case TalerErrorCode.BANK_MISSING_TAN_INFO: return opKnownFailure("no-contact-info", resp);
- case TalerErrorCode.BANK_UNALLOWED_DEBIT: return opKnownFailure("no-enough-balance", resp);
- default: return opUnknownFailure(resp, body)
+ case TalerErrorCode.BANK_TRANSFER_REQUEST_UID_REUSED:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_CONVERSION_AMOUNT_TO_SMALL:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_BAD_CONVERSION:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_UNALLOWED_DEBIT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_CONFIRM_INCOMPLETE:
+ return opKnownTalerFailure(details.code, details);
+ default:
+ return opUnknownFailure(resp, details);
}
}
- case HttpStatusCode.NotImplemented: return opKnownFailure("cashout-not-supported", resp);
- case HttpStatusCode.BadGateway: return opKnownFailure("tan-failed", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.BadGateway: {
+ const details = await readTalerErrorResponse(resp);
+ switch (details.code) {
+ case TalerErrorCode.BANK_TAN_CHANNEL_SCRIPT_FAILED:
+ return opKnownTalerFailure(details.code, details);
+ default:
+ return opUnknownFailure(resp, details);
+ }
+ }
+ case HttpStatusCode.NotImplemented:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
- * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts-$CASHOUT_ID-abort
- *
+ * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts-$CASHOUT_ID
+ *
*/
- async abortCashoutById(auth: UserAndToken, cid: number) {
- const url = new URL(`accounts/${auth.username}/cashouts/${cid}/abort`, this.baseUrl);
+ async getCashoutById(auth: UserAndToken, cid: number) {
+ const url = new URL(
+ `accounts/${auth.username}/cashouts/${cid}`,
+ this.baseUrl,
+ );
const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
+ method: "GET",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
},
});
switch (resp.status) {
- case HttpStatusCode.NoContent: return opEmptySuccess()
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
- case HttpStatusCode.Conflict: return opKnownFailure("already-confirmed", resp);
- case HttpStatusCode.NotImplemented: return opKnownFailure("cashout-not-supported", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForCashoutStatusResponse());
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotImplemented:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
- * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts-$CASHOUT_ID-confirm
- *
+ * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts
+ *
*/
- async confirmCashoutById(auth: UserAndToken, cid: number, body: TalerCorebankApi.CashoutConfirmRequest) {
- const url = new URL(`accounts/${auth.username}/cashouts/${cid}/confirm`, this.baseUrl);
+ async getAccountCashouts(auth: UserAndToken, pagination?: PaginationParams) {
+ const url = new URL(`accounts/${auth.username}/cashouts`, this.baseUrl);
+ addPaginationParams(url, pagination);
const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
+ method: "GET",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
},
- body,
});
switch (resp.status) {
- case HttpStatusCode.NoContent: return opEmptySuccess()
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
- // case HttpStatusCode.Forbidden: return opKnownFailure("wrong-tan-or-credential", resp);
- case HttpStatusCode.Conflict: {
- const body = await resp.json()
- const details = codecForTalerErrorDetail().decode(body)
- switch (details.code) {
- case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT: return opKnownFailure("already-aborted", resp);
- case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return opKnownFailure("no-cashout-payto", resp);
- case TalerErrorCode.BANK_UNALLOWED_DEBIT: return opKnownFailure("no-enough-balance", resp);
- case TalerErrorCode.BANK_BAD_CONVERSION: return opKnownFailure("incorrect-exchange-rate", resp);
- case TalerErrorCode.BANK_TAN_CHALLENGE_FAILED: return opKnownFailure("invalid-code", resp);
- default: return opUnknownFailure(resp, body)
- }
- }
- case HttpStatusCode.TooManyRequests: return opKnownFailure("too-many-attempts", resp);
- case HttpStatusCode.NotImplemented: return opKnownFailure("cashout-not-supported", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForCashouts());
+ case HttpStatusCode.NoContent:
+ return opFixedSuccess({ cashouts: [] });
+ case HttpStatusCode.NotImplemented:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
- * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts-$CASHOUT_ID
- *
+ * https://docs.taler.net/core/api-corebank.html#get--cashouts
+ *
*/
- async getCashoutById(auth: UserAndToken, cid: number) {
- const url = new URL(`accounts/${auth.username}/cashouts/${cid}`, this.baseUrl);
+ async getGlobalCashouts(auth: AccessToken, pagination?: PaginationParams) {
+ const url = new URL(`cashouts`, this.baseUrl);
+ addPaginationParams(url, pagination);
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth),
},
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForCashoutStatusResponse())
- case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
- case HttpStatusCode.NotImplemented: return opKnownFailure("cashout-not-supported", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForGlobalCashouts());
+ case HttpStatusCode.NoContent:
+ return opFixedSuccess({ cashouts: [] });
+ case HttpStatusCode.NotImplemented:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
+ //
+ // 2FA
+ //
+
/**
- * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts
- *
+ * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-challenge-$CHALLENGE_ID
+ *
*/
- async getAccountCashouts(auth: UserAndToken, pagination?: PaginationParams) {
- const url = new URL(`accounts/${auth.username}/cashouts`, this.baseUrl);
- addPaginationParams(url, pagination)
+ async sendChallenge(auth: UserAndToken, cid: string) {
+ const url = new URL(
+ `accounts/${auth.username}/challenge/${cid}`,
+ this.baseUrl,
+ );
const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
+ method: "POST",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth.token)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
},
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForCashouts())
- case HttpStatusCode.NoContent: return opFixedSuccess({ cashouts: [] });
- case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", resp);;
- case HttpStatusCode.NotImplemented: return opKnownFailure("cashout-not-supported", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForTanTransmission());
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.BadGateway: {
+ const details = await readTalerErrorResponse(resp);
+ switch (details.code) {
+ case TalerErrorCode.BANK_TAN_CHANNEL_SCRIPT_FAILED:
+ return opKnownTalerFailure(details.code, details);
+ default:
+ return opUnknownFailure(resp, details);
+ }
+ }
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
- * https://docs.taler.net/core/api-corebank.html#get--cashouts
- *
+ * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-challenge-$CHALLENGE_ID-confirm
+ *
*/
- async getGlobalCashouts(auth: AccessToken, pagination?: PaginationParams) {
- const url = new URL(`cashouts`, this.baseUrl);
- addPaginationParams(url, pagination)
+ async confirmChallenge(
+ auth: UserAndToken,
+ cid: string,
+ body: TalerCorebankApi.ChallengeSolve,
+ ) {
+ const url = new URL(
+ `accounts/${auth.username}/challenge/${cid}/confirm`,
+ this.baseUrl,
+ );
const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
+ method: "POST",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth)
+ Authorization: makeBearerTokenAuthHeader(auth.token),
},
+ body,
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForGlobalCashouts())
- case HttpStatusCode.NoContent: return opFixedSuccess({ cashouts: [] });
- case HttpStatusCode.NotImplemented: return opKnownFailure("cashout-not-supported", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.NoContent:
+ return opEmptySuccess(resp);
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Conflict: {
+ const details = await readTalerErrorResponse(resp);
+ switch (details.code) {
+ case TalerErrorCode.BANK_TAN_CHALLENGE_EXPIRED:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_TAN_CHALLENGE_FAILED:
+ return opKnownTalerFailure(details.code, details);
+ default:
+ return opUnknownFailure(resp, details);
+ }
+ }
+ case HttpStatusCode.TooManyRequests:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
@@ -610,30 +952,43 @@ export class TalerCoreBankHttpClient {
/**
* https://docs.taler.net/core/api-corebank.html#get--monitor
- *
+ *
*/
- async getMonitor(auth: AccessToken, params: { timeframe?: TalerCorebankApi.MonitorTimeframeParam, which?: number } = {}) {
+ async getMonitor(
+ auth: AccessToken,
+ params: {
+ timeframe?: TalerCorebankApi.MonitorTimeframeParam;
+ date?: AbsoluteTime;
+ } = {},
+ ) {
const url = new URL(`monitor`, this.baseUrl);
if (params.timeframe) {
- url.searchParams.set("timeframe", TalerCorebankApi.MonitorTimeframeParam[params.timeframe])
+ url.searchParams.set(
+ "timeframe",
+ TalerCorebankApi.MonitorTimeframeParam[params.timeframe],
+ );
}
- if (params.which) {
- url.searchParams.set("which", String(params.which))
+ if (params.date) {
+ const { t_s: seconds } = AbsoluteTime.toProtocolTimestamp(params.date);
+ if (seconds !== "never") {
+ url.searchParams.set("date_s", String(seconds));
+ }
}
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- Authorization: makeBearerTokenAuthHeader(auth)
+ Authorization: makeBearerTokenAuthHeader(auth),
},
});
switch (resp.status) {
- case HttpStatusCode.Ok: return opSuccess(resp, codecForMonitorResponse())
- case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", resp);
- case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp);
- //FIXME remove when server is updated
- //FIXME: should be 404 ?
- case HttpStatusCode.ServiceUnavailable: return opKnownFailure("monitor-not-supported", resp);
- default: return opUnknownFailure(resp, await resp.text())
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForMonitorResponse());
+ case HttpStatusCode.BadRequest:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
@@ -643,46 +998,41 @@ export class TalerCoreBankHttpClient {
/**
* https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api
- *
+ *
*/
- getIntegrationAPI(): TalerBankIntegrationHttpClient {
- const url = new URL(`taler-integration/`, this.baseUrl);
- return new TalerBankIntegrationHttpClient(url.href, this.httpLib)
+ getIntegrationAPI(): URL {
+ return new URL(`taler-integration/`, this.baseUrl);
}
/**
* https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api
- *
+ *
*/
- getWireGatewayAPI(username: string): TalerWireGatewayHttpClient {
- const url = new URL(`accounts/${username}/taler-wire-gateway/`, this.baseUrl);
- return new TalerWireGatewayHttpClient(url.href, username, this.httpLib)
+ getWireGatewayAPI(username: string): URL {
+ return new URL(`accounts/${username}/taler-wire-gateway/`, this.baseUrl);
}
/**
- * https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api
- *
- */
- getRevenueAPI(username: string): TalerRevenueHttpClient {
- const url = new URL(`accounts/${username}/taler-revenue/`, this.baseUrl);
- return new TalerRevenueHttpClient(url.href, username, this.httpLib,)
+ * https://docs.taler.net/core/api-corebank.html#taler-bank-integration-api
+ *
+ */
+ getRevenueAPI(username: string): URL {
+ return new URL(`accounts/${username}/taler-revenue/`, this.baseUrl);
}
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
- *
- */
- getAuthenticationAPI(username: string): TalerAuthenticationHttpClient {
- const url = new URL(`accounts/${username}/`, this.baseUrl);
- return new TalerAuthenticationHttpClient(url.href, username, this.httpLib,)
+ *
+ */
+ getAuthenticationAPI(username: string): URL {
+ return new URL(`accounts/${username}/`, this.baseUrl);
}
/**
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token
- *
- */
- getConversionInfoAPI(): TalerBankConversionHttpClient {
- const url = new URL(`conversion-info/`, this.baseUrl);
- return new TalerBankConversionHttpClient(url.href, this.httpLib)
+ *
+ */
+ getConversionInfoAPI(): URL {
+ return new URL(`conversion-info/`, this.baseUrl);
}
}