/* This file is part of GNU Taler (C) 2022 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 */ import { AmountJson, Amounts, Logger } from "@gnu-taler/taler-util"; import { createPlatformHttpLib, expectSuccessResponseOrThrow, HttpRequestLibrary, readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http"; import { AccessToken, codecForAccountData, codecForBankAccountCreateWithdrawalResponse, codecForBankAccountGetWithdrawalResponse, codecForBankAccountTransactionInfo, codecForBankAccountTransactionsResponse, codecForCashoutConversionResponse, codecForCashoutPending, codecForCashouts, codecForCashoutStatusResponse, codecForConversionRatesResponse, codecForCoreBankConfig, codecForGlobalCashouts, codecForListBankAccountsResponse, codecForMonitorResponse, codecForPublicAccountsResponse, codecForTokenSuccessResponse, TalerAuthentication, TalerCorebankApi } from "./types.js"; import { addPaginationParams, makeBasicAuthHeader, makeBearerTokenAuthHeader, PaginationParams, UserAndPassword, UserAndToken } from "./utils.js"; import { TalerRevenueHttpClient } from "./bank-revenue.js"; import { TalerWireGatewayHttpClient } from "./bank-wire.js"; import { TalerBankIntegrationHttpClient } from "./bank-integration.js"; const logger = new Logger("http-client/core-bank.ts"); export class TalerCoreBankHttpClient { httpLib: HttpRequestLibrary; constructor( private baseUrl: string, httpClient?: HttpRequestLibrary, ) { this.httpLib = httpClient ?? createPlatformHttpLib(); } /** * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token * * @returns */ async createAccessToken( auth: UserAndPassword, body: TalerAuthentication.TokenRequest, ): Promise { const url = new URL(`accounts/${auth.username}/token`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", headers: { Authorization: makeBasicAuthHeader(auth.username, auth.password), }, body }); return readSuccessResponseJsonOrThrow(resp, codecForTokenSuccessResponse()); } async deleteAccessToken( auth: UserAndToken, ): Promise { const url = new URL(`accounts/${auth.username}/token`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "DELETE", headers: { Authorization: makeBearerTokenAuthHeader(auth.token), } }); return expectSuccessResponseOrThrow(resp); } /** * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME * */ async getConfig(): Promise { const url = new URL(`config`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "GET" }); return readSuccessResponseJsonOrThrow(resp, codecForCoreBankConfig()); } // // ACCOUNTS // /** * https://docs.taler.net/core/api-corebank.html#post--accounts * */ async createAccount(auth: AccessToken, body: TalerCorebankApi.RegisterAccountRequest): Promise { const url = new URL(`accounts`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", body, headers: { Authorization: makeBearerTokenAuthHeader(auth) }, }); return expectSuccessResponseOrThrow(resp); } /** * https://docs.taler.net/core/api-corebank.html#delete--accounts-$USERNAME * */ async deleteAccount(auth: UserAndToken): Promise { const url = new URL(`accounts/${auth.username}`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "DELETE", headers: { Authorization: makeBearerTokenAuthHeader(auth.token) }, }); return expectSuccessResponseOrThrow(resp); } /** * https://docs.taler.net/core/api-corebank.html#patch--accounts-$USERNAME * */ async updateAccount(auth: UserAndToken, body: TalerCorebankApi.AccountReconfiguration): Promise { 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) }, }); return expectSuccessResponseOrThrow(resp); } /** * https://docs.taler.net/core/api-corebank.html#patch--accounts-$USERNAME-auth * */ async updatePassword(auth: UserAndToken, body: TalerCorebankApi.AccountPasswordChange): Promise { 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) }, }); return expectSuccessResponseOrThrow(resp); } /** * https://docs.taler.net/core/get-$BANK_API_BASE_URL-public-accounts * */ async getPublicAccounts(): Promise { const url = new URL(`public-accounts`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "GET", headers: { }, }); return readSuccessResponseJsonOrThrow(resp, codecForPublicAccountsResponse()); } /** * https://docs.taler.net/core/api-corebank.html#get--accounts * */ async getAccounts(auth: AccessToken): Promise { const url = new URL(`accounts`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "GET", headers: { Authorization: makeBearerTokenAuthHeader(auth) }, }); return readSuccessResponseJsonOrThrow(resp, codecForListBankAccountsResponse()); } /** * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME * */ async getAccount(auth: UserAndToken): Promise { const url = new URL(`accounts/${auth.username}`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "GET", headers: { Authorization: makeBearerTokenAuthHeader(auth.token) }, }); return readSuccessResponseJsonOrThrow(resp, codecForAccountData()); } // // TRANSACTIONS // /** * https://docs.taler.net/core/api-corebank.html#get-$BANK_API_BASE_URL-accounts-$account_name-transactions * */ async getTransactions(auth: UserAndToken, pagination?: PaginationParams): Promise { const url = new URL(`accounts/${auth.username}/transactions`, this.baseUrl); addPaginationParams(url, pagination) const resp = await this.httpLib.fetch(url.href, { method: "GET", headers: { Authorization: makeBearerTokenAuthHeader(auth.token) }, }); return readSuccessResponseJsonOrThrow(resp, codecForBankAccountTransactionsResponse()); } /** * https://docs.taler.net/core/api-corebank.html#get-$BANK_API_BASE_URL-accounts-$account_name-transactions-$transaction_id * */ async getTransactionById(auth: UserAndToken, txid: number): Promise { 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) }, }); return readSuccessResponseJsonOrThrow(resp, codecForBankAccountTransactionInfo()); } /** * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-transactions * */ async createTransaction(auth: UserAndToken, body: TalerCorebankApi.CreateBankAccountTransactionCreate): Promise { const url = new URL(`accounts/${auth.username}/transactions`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", headers: { Authorization: makeBearerTokenAuthHeader(auth.token) }, body, }); return expectSuccessResponseOrThrow(resp); } // // WITHDRAWALS // /** * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-withdrawals * */ async createWithdrawal(auth: UserAndToken, body: TalerCorebankApi.BankAccountCreateWithdrawalRequest): Promise { 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) }, body, }); return readSuccessResponseJsonOrThrow(resp, codecForBankAccountCreateWithdrawalResponse()); } /** * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-accounts-$account_name-withdrawals * */ async getWithdrawalById(wid: string): Promise { const url = new URL(`withdrawals/${wid}`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "GET", }); return readSuccessResponseJsonOrThrow(resp, codecForBankAccountGetWithdrawalResponse()); } /** * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-withdrawals-$withdrawal_id-abort * */ async abortWithdrawalById(wid: string): Promise { const url = new URL(`withdrawals/${wid}/abort`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", }); return expectSuccessResponseOrThrow(resp); } /** * https://docs.taler.net/core/api-corebank.html#post-$BANK_API_BASE_URL-withdrawals-$withdrawal_id-confirm * */ async confirmWithdrawalById(wid: string): Promise { const url = new URL(`withdrawals/${wid}/confirm`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", }); return expectSuccessResponseOrThrow(resp); } // // CASHOUTS // /** * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts * */ async createCashout(auth: UserAndToken, body: TalerCorebankApi.CashoutRequest): Promise { 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) }, body, }); return readSuccessResponseJsonOrThrow(resp, codecForCashoutPending()); } /** * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts-$CASHOUT_ID-abort * */ async abortCashoutById(auth: UserAndToken, cid: string): Promise { const url = new URL(`accounts/${auth.username}/cashouts/${cid}/abort`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", headers: { Authorization: makeBearerTokenAuthHeader(auth.token) }, }); return expectSuccessResponseOrThrow(resp); } /** * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts-$CASHOUT_ID-confirm * */ async confirmCashoutById(auth: UserAndToken, cid: string, body: TalerCorebankApi.CashoutConfirmRequest): Promise { const url = new URL(`accounts/${auth.username}/cashouts/${cid}/confirm`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "POST", headers: { Authorization: makeBearerTokenAuthHeader(auth.token) }, body, }); return expectSuccessResponseOrThrow(resp); } /** * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts-$CASHOUT_ID-confirm * */ async getCashoutRate(conversion: { debit?: AmountJson, credit?: AmountJson }): Promise { const url = new URL(`cashout-rate`, this.baseUrl); if (conversion.debit) { url.searchParams.set("amount_debit", Amounts.stringify(conversion.debit)) } if (conversion.credit) { url.searchParams.set("amount_debit", Amounts.stringify(conversion.credit)) } const resp = await this.httpLib.fetch(url.href, { method: "GET", }); return readSuccessResponseJsonOrThrow(resp, codecForCashoutConversionResponse()); } /** * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts * */ async getAccountCashouts(auth: UserAndToken): Promise { const url = new URL(`accounts/${auth.username}/cashouts`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "GET", headers: { Authorization: makeBearerTokenAuthHeader(auth.token) }, }); return readSuccessResponseJsonOrThrow(resp, codecForCashouts()); } /** * https://docs.taler.net/core/api-corebank.html#get--cashouts * */ async getGlobalCashouts(auth: AccessToken): Promise { const url = new URL(`cashouts`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "GET", headers: { Authorization: makeBearerTokenAuthHeader(auth) }, }); return readSuccessResponseJsonOrThrow(resp, codecForGlobalCashouts()); } /** * https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts-$CASHOUT_ID * */ async getCashoutById(auth: UserAndToken, cid: string): Promise { const url = new URL(`accounts/${auth.username}/cashouts/${cid}`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "GET", headers: { Authorization: makeBearerTokenAuthHeader(auth.token) }, }); return readSuccessResponseJsonOrThrow(resp, codecForCashoutStatusResponse()); } // // CONVERSION RATE // /** * https://docs.taler.net/core/api-corebank.html#get--conversion-rates * */ async getConversionRates(): Promise { const url = new URL(`conversion-rates`, this.baseUrl); const resp = await this.httpLib.fetch(url.href, { method: "GET", }); return readSuccessResponseJsonOrThrow(resp, codecForConversionRatesResponse()); } // // MONITOR // /** * https://docs.taler.net/core/api-corebank.html#get--monitor * */ async getMonitor(params: { timeframe: TalerCorebankApi.MonitorTimeframeParam, which: number }): Promise { const url = new URL(`monitor`, this.baseUrl); url.searchParams.set("timeframe", params.timeframe.toString()) url.searchParams.set("which", String(params.which)) const resp = await this.httpLib.fetch(url.href, { method: "GET", }); return readSuccessResponseJsonOrThrow(resp, codecForMonitorResponse()); } // // Others API // /** * 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) } /** * 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) } /** * 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,) } }