diff options
author | Özgür Kesim <oec-taler@kesim.org> | 2023-09-09 07:34:11 +0200 |
---|---|---|
committer | Özgür Kesim <oec-taler@kesim.org> | 2023-09-09 07:34:11 +0200 |
commit | 5495551071a3fdc36c38deb4c1cf6f4aa5b98bd4 (patch) | |
tree | adf7730b190618a0499e50a2d43cf1b850cddd16 /packages/taler-wallet-core/src/bank-api-client.ts | |
parent | 94cfcc875065f988815c31aaf8ebf36f75ac5983 (diff) | |
parent | 6c3cfa9be7a332c2cc8490f25ebd6c73c8244842 (diff) |
Merge branch 'master' into age-withdraw
Diffstat (limited to 'packages/taler-wallet-core/src/bank-api-client.ts')
-rw-r--r-- | packages/taler-wallet-core/src/bank-api-client.ts | 500 |
1 files changed, 0 insertions, 500 deletions
diff --git a/packages/taler-wallet-core/src/bank-api-client.ts b/packages/taler-wallet-core/src/bank-api-client.ts deleted file mode 100644 index 3174667f1..000000000 --- a/packages/taler-wallet-core/src/bank-api-client.ts +++ /dev/null @@ -1,500 +0,0 @@ -/* - 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 <http://www.gnu.org/licenses/> - */ - -/** - * Client for the Taler (demo-)bank. - */ - -/** - * Imports. - */ -import { - AmountString, - base64FromArrayBuffer, - buildCodecForObject, - Codec, - codecForAny, - codecForString, - encodeCrock, - generateIban, - getRandomBytes, - j2s, - Logger, - stringToBytes, - TalerError, - TalerErrorCode, -} from "@gnu-taler/taler-util"; -import { - checkSuccessResponseOrThrow, - createPlatformHttpLib, - HttpRequestLibrary, - readSuccessResponseJsonOrThrow, -} from "@gnu-taler/taler-util/http"; - -const logger = new Logger("bank-api-client.ts"); - -export enum CreditDebitIndicator { - Credit = "credit", - Debit = "debit", -} - -export interface BankAccountBalanceResponse { - balance: { - amount: AmountString; - credit_debit_indicator: CreditDebitIndicator; - }; -} - -export interface BankServiceHandle { - readonly bankAccessApiBaseUrl: string; - readonly http: HttpRequestLibrary; -} - -export interface BankUser { - username: string; - password: string; - accountPaytoUri: string; -} - -export interface WithdrawalOperationInfo { - withdrawal_id: string; - taler_withdraw_uri: string; -} - -/** - * FIXME: Rename, this is not part of the integration test harness anymore. - */ -export interface HarnessExchangeBankAccount { - accountName: string; - accountPassword: string; - accountPaytoUri: string; - wireGatewayApiBaseUrl: string; -} - -/** - * Helper function to generate the "Authorization" HTTP header. - */ -function makeBasicAuthHeader(username: string, password: string): string { - const auth = `${username}:${password}`; - const authEncoded: string = base64FromArrayBuffer(stringToBytes(auth)); - return `Basic ${authEncoded}`; -} - -const codecForWithdrawalOperationInfo = (): Codec<WithdrawalOperationInfo> => - buildCodecForObject<WithdrawalOperationInfo>() - .property("withdrawal_id", codecForString()) - .property("taler_withdraw_uri", codecForString()) - .build("WithdrawalOperationInfo"); - -/** - * @deprecated Use BankAccessApiClient or WireGatewayApi - */ -export namespace BankApi { - // FIXME: Move to BankAccessApi?! - export async function registerAccount( - bank: BankServiceHandle, - username: string, - password: string, - options: { - iban?: string; - }, - ): Promise<BankUser> { - const url = new URL("testing/register", bank.bankAccessApiBaseUrl); - const resp = await bank.http.postJson(url.href, { - username, - password, - iban: options?.iban, - }); - 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( - TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR, - { - httpStatusCode: resp.status, - }, - ); - } - 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 - } - return { - password, - username, - accountPaytoUri: paytoUri, - }; - } - - // FIXME: Move to BankAccessApi?! - export async function createRandomBankUser( - bank: BankServiceHandle, - ): Promise<BankUser> { - 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 registerAccount(bank, username, password, { - iban, - }); - } - - export async function confirmWithdrawalOperation( - bank: BankServiceHandle, - bankUser: BankUser, - wopi: WithdrawalOperationInfo, - ): Promise<void> { - const url = new URL( - `accounts/${bankUser.username}/withdrawals/${wopi.withdrawal_id}/confirm`, - bank.bankAccessApiBaseUrl, - ); - logger.info(`confirming withdrawal operation via ${url.href}`); - const resp = await bank.http.postJson( - url.href, - {}, - { - headers: { - Authorization: makeBasicAuthHeader( - bankUser.username, - bankUser.password, - ), - }, - }, - ); - - logger.info(`response status ${resp.status}`); - const respJson = await readSuccessResponseJsonOrThrow(resp, codecForAny()); - - // FIXME: We don't check the status here! - } - - export async function abortWithdrawalOperation( - bank: BankServiceHandle, - bankUser: BankUser, - wopi: WithdrawalOperationInfo, - ): Promise<void> { - const url = new URL( - `accounts/${bankUser.username}/withdrawals/${wopi.withdrawal_id}/abort`, - bank.bankAccessApiBaseUrl, - ); - const resp = await bank.http.postJson( - url.href, - {}, - { - headers: { - Authorization: makeBasicAuthHeader( - bankUser.username, - bankUser.password, - ), - }, - }, - ); - await readSuccessResponseJsonOrThrow(resp, codecForAny()); - } -} - -/** - * @deprecated use BankAccessApiClient - */ -export namespace BankAccessApi { - export async function getAccountBalance( - bank: BankServiceHandle, - bankUser: BankUser, - ): Promise<BankAccountBalanceResponse> { - const url = new URL( - `accounts/${bankUser.username}`, - bank.bankAccessApiBaseUrl, - ); - const resp = await bank.http.fetch(url.href, { - headers: { - Authorization: makeBasicAuthHeader( - bankUser.username, - bankUser.password, - ), - }, - }); - return await resp.json(); - } - - export async function createWithdrawalOperation( - bank: BankServiceHandle, - bankUser: BankUser, - amount: string, - ): Promise<WithdrawalOperationInfo> { - const url = new URL( - `accounts/${bankUser.username}/withdrawals`, - bank.bankAccessApiBaseUrl, - ); - const resp = await bank.http.postJson( - url.href, - { - amount, - }, - { - headers: { - Authorization: makeBasicAuthHeader( - bankUser.username, - bankUser.password, - ), - }, - }, - ); - return readSuccessResponseJsonOrThrow( - resp, - codecForWithdrawalOperationInfo(), - ); - } -} - -export interface BankAccessApiClientArgs { - baseUrl: string; - auth?: { username: string; password: string }; - enableThrottling?: boolean; - allowHttp?: boolean; -} - -export interface BankAccessApiCreateTransactionRequest { - amount: AmountString; - paytoUri: string; -} - -export class WireGatewayApiClientArgs { - accountName: string; - accountPassword: string; - wireGatewayApiBaseUrl: string; - enableThrottling?: boolean; - allowHttp?: boolean; -} - -/** - * This API look like it belongs to harness - * but it will be nice to have in utils to be used by others - */ -export class WireGatewayApiClient { - httpLib; - - constructor(private args: WireGatewayApiClientArgs) { - this.httpLib = createPlatformHttpLib({ - enableThrottling: !!args.enableThrottling, - allowHttp: !!args.allowHttp, - }); - } - - async adminAddIncoming(params: { - amount: string; - reservePub: string; - debitAccountPayto: string; - }): Promise<void> { - let url = new URL(`admin/add-incoming`, this.args.wireGatewayApiBaseUrl); - const resp = await this.httpLib.fetch(url.href, { - method: "POST", - body: { - amount: params.amount, - reserve_pub: params.reservePub, - debit_account: params.debitAccountPayto, - }, - headers: { - Authorization: makeBasicAuthHeader( - this.args.accountName, - this.args.accountPassword, - ), - }, - }); - logger.info(`add-incoming response status: ${resp.status}`); - await checkSuccessResponseOrThrow(resp); - } -} - -/** - * This API look like it belongs to harness - * but it will be nice to have in utils to be used by others - */ -export class BankAccessApiClient { - httpLib: HttpRequestLibrary; - - constructor(private args: BankAccessApiClientArgs) { - this.httpLib = createPlatformHttpLib({ - enableThrottling: !!args.enableThrottling, - allowHttp: !!args.allowHttp, - }); - } - - setAuth(auth: { username: string; password: string }) { - this.args.auth = auth; - } - - private makeAuthHeader(): Record<string, string> { - if (!this.args.auth) { - return {}; - } - const authHeaderValue = makeBasicAuthHeader( - this.args.auth.username, - this.args.auth.password, - ); - return { - Authorization: authHeaderValue, - }; - } - - async getTransactions(username: string): Promise<void> { - const auth = this.args.auth; - const reqUrl = new URL( - `accounts/${username}/transactions`, - this.args.baseUrl, - ); - const resp = await this.httpLib.fetch(reqUrl.href, { - method: "GET", - headers: { - ...this.makeAuthHeader(), - }, - }); - - const res = await readSuccessResponseJsonOrThrow(resp, codecForAny()); - logger.info(`result: ${j2s(res)}`); - } - - async createTransaction( - username: string, - req: BankAccessApiCreateTransactionRequest, - ): Promise<any> { - const reqUrl = new URL( - `accounts/${username}/transactions`, - this.args.baseUrl, - ); - - const resp = await this.httpLib.fetch(reqUrl.href, { - method: "POST", - body: req, - headers: this.makeAuthHeader(), - }); - - return await readSuccessResponseJsonOrThrow(resp, codecForAny()); - } - - async registerAccount( - username: string, - password: string, - options: { - iban?: string; - }, - ): Promise<BankUser> { - const url = new URL("testing/register", this.args.baseUrl); - const resp = await this.httpLib.fetch(url.href, { - method: "POST", - body: { - username, - password, - iban: options?.iban, - }, - }); - 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( - TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR, - { - httpStatusCode: resp.status, - }, - ); - } - 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 - } - return { - password, - username, - accountPaytoUri: paytoUri, - }; - } - - async createRandomBankUser(): Promise<BankUser> { - 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, - }); - } - - async createWithdrawalOperation( - user: string, - amount: string, - ): Promise<WithdrawalOperationInfo> { - const url = new URL(`accounts/${user}/withdrawals`, this.args.baseUrl); - const resp = await this.httpLib.fetch(url.href, { - method: "POST", - body: { - amount, - }, - headers: this.makeAuthHeader(), - }); - return readSuccessResponseJsonOrThrow( - resp, - codecForWithdrawalOperationInfo(), - ); - } - - async confirmWithdrawalOperation( - username: string, - wopi: WithdrawalOperationInfo, - ): Promise<void> { - const url = new URL( - `accounts/${username}/withdrawals/${wopi.withdrawal_id}/confirm`, - this.args.baseUrl, - ); - logger.info(`confirming withdrawal operation via ${url.href}`); - const resp = await this.httpLib.fetch(url.href, { - method: "POST", - body: {}, - headers: this.makeAuthHeader(), - }); - - logger.info(`response status ${resp.status}`); - const respJson = await readSuccessResponseJsonOrThrow(resp, codecForAny()); - - // FIXME: We don't check the status here! - } - - async abortWithdrawalOperation( - accountName: string, - wopi: WithdrawalOperationInfo, - ): Promise<void> { - const url = new URL( - `accounts/${accountName}/withdrawals/${wopi.withdrawal_id}/abort`, - this.args.baseUrl, - ); - const resp = await this.httpLib.fetch(url.href, { - method: "POST", - body: {}, - headers: this.makeAuthHeader(), - }); - await readSuccessResponseJsonOrThrow(resp, codecForAny()); - } -} |