aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-util/src/http-client
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-util/src/http-client')
-rw-r--r--packages/taler-util/src/http-client/authentication.ts33
-rw-r--r--packages/taler-util/src/http-client/bank-core.ts46
-rw-r--r--packages/taler-util/src/http-client/bank-integration.ts2
-rw-r--r--packages/taler-util/src/http-client/bank-revenue.ts32
-rw-r--r--packages/taler-util/src/http-client/bank-wire.ts108
-rw-r--r--packages/taler-util/src/http-client/challenger.ts2
-rw-r--r--packages/taler-util/src/http-client/exchange.ts780
-rw-r--r--packages/taler-util/src/http-client/merchant.ts71
-rw-r--r--packages/taler-util/src/http-client/officer-account.ts35
-rw-r--r--packages/taler-util/src/http-client/utils.ts70
10 files changed, 883 insertions, 296 deletions
diff --git a/packages/taler-util/src/http-client/authentication.ts b/packages/taler-util/src/http-client/authentication.ts
index fa48f3da6..7e3297ff0 100644
--- a/packages/taler-util/src/http-client/authentication.ts
+++ b/packages/taler-util/src/http-client/authentication.ts
@@ -88,9 +88,37 @@ export class TalerAuthenticationHttpClient {
}
/**
- *
+ * FIXME: merge this with createAccessTokenBearer the protocol of both
+ * services need to reply the same
+ *
* @returns
*/
+ async createAccessTokenBearer_BANK(token: AccessToken, body: TokenRequest) {
+ const url = new URL(`token`, this.baseUrl);
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ headers: {
+ Authorization: makeBearerTokenAuthHeader(token),
+ },
+ body,
+ });
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForTokenSuccessResponse());
+ //FIXME: missing in docs
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+ }
+ }
+
+ /**
+ *
+ * @returns
+ */
async createAccessTokenBearer(token: AccessToken, body: TokenRequest) {
const url = new URL(`token`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
@@ -125,6 +153,9 @@ export class TalerAuthenticationHttpClient {
case HttpStatusCode.Ok:
return opEmptySuccess(resp);
//FIXME: missing in docs
+ case HttpStatusCode.NoContent:
+ return opEmptySuccess(resp);
+ //FIXME: missing in docs
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
default:
diff --git a/packages/taler-util/src/http-client/bank-core.ts b/packages/taler-util/src/http-client/bank-core.ts
index 2639018a8..2fef0adb6 100644
--- a/packages/taler-util/src/http-client/bank-core.ts
+++ b/packages/taler-util/src/http-client/bank-core.ts
@@ -68,7 +68,6 @@ import {
} from "../types-taler-corebank.js";
import {
CacheEvictor,
- IdempotencyRetry,
addLongPollingParam,
addPaginationParams,
makeBearerTokenAuthHeader,
@@ -129,7 +128,8 @@ export class TalerCoreBankHttpClient {
*
*/
async getConfig(): Promise<
- OperationFail<HttpStatusCode.NotFound> | OperationOk<TalerCorebankApi.TalerCorebankConfigResponse>
+ | OperationFail<HttpStatusCode.NotFound>
+ | OperationOk<TalerCorebankApi.TalerCorebankConfigResponse>
> {
const url = new URL(`config`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
@@ -230,6 +230,10 @@ export class TalerCoreBankHttpClient {
return opKnownTalerFailure(details.code, details);
case TalerErrorCode.BANK_MISSING_TAN_INFO:
return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_PASSWORD_TOO_SHORT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_PASSWORD_TOO_LONG:
+ return opKnownTalerFailure(details.code, details);
default:
return opUnknownFailure(resp, details);
}
@@ -326,6 +330,10 @@ export class TalerCoreBankHttpClient {
return opKnownTalerFailure(details.code, details);
case TalerErrorCode.BANK_MISSING_TAN_INFO:
return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_PASSWORD_TOO_SHORT:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_PASSWORD_TOO_LONG:
+ return opKnownTalerFailure(details.code, details);
default:
return opUnknownFailure(resp, details);
}
@@ -538,7 +546,6 @@ export class TalerCoreBankHttpClient {
async createTransaction(
auth: UserAndToken,
body: TalerCorebankApi.CreateTransactionRequest,
- idempotencyCheck: IdempotencyRetry | undefined,
cid?: string,
): Promise<
//manually definition all return types because of recursion
@@ -554,9 +561,6 @@ export class TalerCoreBankHttpClient {
| 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: {
@@ -592,11 +596,7 @@ export class TalerCoreBankHttpClient {
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);
+ return opKnownTalerFailure(details.code, details);
default:
return opUnknownFailure(resp, details);
}
@@ -648,7 +648,12 @@ export class TalerCoreBankHttpClient {
* https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-confirm
*
*/
- async confirmWithdrawalById(auth: UserAndToken, wid: string, cid?: string) {
+ async confirmWithdrawalById(
+ auth: UserAndToken,
+ body: TalerCorebankApi.BankAccountConfirmWithdrawalRequest,
+ wid: string,
+ cid?: string,
+ ) {
const url = new URL(
`accounts/${auth.username}/withdrawals/${wid}/confirm`,
this.baseUrl,
@@ -659,6 +664,7 @@ export class TalerCoreBankHttpClient {
Authorization: makeBearerTokenAuthHeader(auth.token),
"X-Challenge-Id": cid,
},
+ body,
});
switch (resp.status) {
case HttpStatusCode.Accepted:
@@ -683,6 +689,10 @@ export class TalerCoreBankHttpClient {
return opKnownTalerFailure(details.code, details);
case TalerErrorCode.BANK_UNALLOWED_DEBIT:
return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_AMOUNT_DIFFERS:
+ return opKnownTalerFailure(details.code, details);
+ case TalerErrorCode.BANK_AMOUNT_REQUIRED:
+ return opKnownTalerFailure(details.code, details);
default:
return opUnknownFailure(resp, details);
}
@@ -794,10 +804,10 @@ export class TalerCoreBankHttpClient {
switch (details.code) {
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_CONVERSION_AMOUNT_TO_SMALL:
+ return opKnownTalerFailure(details.code, details);
case TalerErrorCode.BANK_UNALLOWED_DEBIT:
return opKnownTalerFailure(details.code, details);
case TalerErrorCode.BANK_CONFIRM_INCOMPLETE:
@@ -816,7 +826,13 @@ export class TalerCoreBankHttpClient {
}
}
case HttpStatusCode.NotImplemented:
- return opKnownHttpFailure(resp.status, resp);
+ const details = await readTalerErrorResponse(resp);
+ switch (details.code) {
+ case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED:
+ return opKnownTalerFailure(details.code, details);
+ default:
+ return opKnownHttpFailure(resp.status, resp);
+ }
default:
return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
diff --git a/packages/taler-util/src/http-client/bank-integration.ts b/packages/taler-util/src/http-client/bank-integration.ts
index 8e98bb783..9bcdac683 100644
--- a/packages/taler-util/src/http-client/bank-integration.ts
+++ b/packages/taler-util/src/http-client/bank-integration.ts
@@ -155,7 +155,7 @@ export class TalerBankIntegrationHttpClient {
return opKnownTalerFailure(details.code, details);
case TalerErrorCode.BANK_AMOUNT_DIFFERS:
return opKnownTalerFailure(details.code, details);
- case TalerErrorCode.BANK_AMOUNT_REQUIRED:
+ case TalerErrorCode.BANK_UNALLOWED_DEBIT:
return opKnownTalerFailure(details.code, details);
default:
return opUnknownFailure(resp, details);
diff --git a/packages/taler-util/src/http-client/bank-revenue.ts b/packages/taler-util/src/http-client/bank-revenue.ts
index 6acff91f6..dfa007fa1 100644
--- a/packages/taler-util/src/http-client/bank-revenue.ts
+++ b/packages/taler-util/src/http-client/bank-revenue.ts
@@ -30,12 +30,21 @@ import {
opSuccessFromHttp,
opUnknownFailure,
} from "../operation.js";
-import { LongPollParams, PaginationParams } from "../types-taler-common.js";
+import {
+ AccessToken,
+ LongPollParams,
+ PaginationParams,
+} from "../types-taler-common.js";
import {
codecForRevenueConfig,
codecForRevenueIncomingHistory,
} from "../types-taler-revenue.js";
-import { addLongPollingParam, addPaginationParams } from "./utils.js";
+import {
+ addLongPollingParam,
+ addPaginationParams,
+ BasicOrTokenAuth,
+ createAuthorizationHeader,
+} from "./utils.js";
export type TalerBankRevenueResultByMethod<
prop extends keyof TalerRevenueHttpClient,
@@ -44,10 +53,7 @@ export type TalerBankRevenueErrorsByMethod<
prop extends keyof TalerRevenueHttpClient,
> = FailCasesByMethod<TalerRevenueHttpClient, prop>;
-type UsernameAndPassword = {
- username: string;
- password: string;
-};
+
/**
* The API is used by the merchant (or other parties) to query
* for incoming transactions to their account.
@@ -62,7 +68,7 @@ export class TalerRevenueHttpClient {
this.httpLib = httpClient ?? createPlatformHttpLib();
}
- public readonly PROTOCOL_VERSION = "0:0:0";
+ public readonly PROTOCOL_VERSION = "1:0:0";
isCompatible(version: string): boolean {
const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version);
@@ -73,14 +79,12 @@ export class TalerRevenueHttpClient {
* https://docs.taler.net/core/api-bank-revenue.html#get--config
*
*/
- async getConfig(auth?: UsernameAndPassword) {
+ async getConfig(auth?: BasicOrTokenAuth) {
const url = new URL(`config`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- Authorization: auth
- ? makeBasicAuthHeader(auth.username, auth.password)
- : undefined,
+ Authorization: createAuthorizationHeader(auth),
},
});
switch (resp.status) {
@@ -100,7 +104,7 @@ export class TalerRevenueHttpClient {
* @returns
*/
async getHistory(
- auth?: UsernameAndPassword,
+ auth?: BasicOrTokenAuth,
params?: PaginationParams & LongPollParams,
) {
const url = new URL(`history`, this.baseUrl);
@@ -109,9 +113,7 @@ export class TalerRevenueHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- Authorization: auth
- ? makeBasicAuthHeader(auth.username, auth.password)
- : undefined,
+ Authorization: createAuthorizationHeader(auth),
},
});
switch (resp.status) {
diff --git a/packages/taler-util/src/http-client/bank-wire.ts b/packages/taler-util/src/http-client/bank-wire.ts
index 84df50208..c002bd125 100644
--- a/packages/taler-util/src/http-client/bank-wire.ts
+++ b/packages/taler-util/src/http-client/bank-wire.ts
@@ -34,6 +34,7 @@ import {
codecForIncomingHistory,
codecForOutgoingHistory,
codecForTransferResponse,
+ codecForBankWireTransferList,
} from "../types-taler-wire-gateway.js";
import { addLongPollingParam, addPaginationParams } from "./utils.js";
@@ -89,7 +90,10 @@ export class TalerWireGatewayHttpClient {
* https://docs.taler.net/core/api-bank-wire.html#post--transfer
*
*/
- async transfer(auth: string, body: TalerWireGatewayApi.TransferRequest) {
+ async makeWireTransfer(
+ auth: string,
+ body: TalerWireGatewayApi.TransferRequest,
+ ) {
const url = new URL(`transfer`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
@@ -117,6 +121,79 @@ export class TalerWireGatewayHttpClient {
}
/**
+ * https://docs.taler.net/core/api-bank-wire.html#get--transfers
+ *
+ */
+ async getTransfers(
+ auth: string,
+ params?: {
+ status?: TalerWireGatewayApi.WireTransferStatus;
+ } & PaginationParams,
+ ) {
+ const url = new URL(`transfers`, this.baseUrl);
+ if (params) {
+ if (params.status) {
+ url.searchParams.set("status", params.status);
+ }
+ }
+ addPaginationParams(url, params);
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "GET",
+ headers: {
+ Authorization: makeBasicAuthHeader(this.username, auth),
+ },
+ });
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForBankWireTransferList());
+ //FIXME: account should not be returned or make it optional
+ case HttpStatusCode.NoContent:
+ return opFixedSuccess({
+ transfers: [],
+ debit_account: undefined,
+ });
+ //FIXME: show more details in docs
+ case HttpStatusCode.BadRequest:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ //FIXME: show more details in docs
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+ }
+ }
+
+ /**
+ * https://docs.taler.net/core/api-bank-wire.html#get--transfers-$ROW_ID
+ *
+ */
+ async getTransferStatus(auth: string, rowId?: number) {
+ const url = new URL(`transfers/${String(rowId)}`, this.baseUrl);
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "GET",
+ headers: {
+ Authorization: makeBasicAuthHeader(this.username, auth),
+ },
+ });
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForBankWireTransferList());
+ //FIXME: account should not be returned or make it optional
+ case HttpStatusCode.BadRequest:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ //FIXME: show more details in docs
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+ }
+ }
+
+ /**
* https://docs.taler.net/core/api-bank-wire.html#get--history-incoming
*
*/
@@ -227,4 +304,33 @@ export class TalerWireGatewayHttpClient {
return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
+
+ /**
+ * https://docs.taler.net/core/api-bank-wire.html#post--admin-add-kycauth
+ *
+ */
+ async addKycAuth(auth: string, body: TalerWireGatewayApi.AddIncomingRequest) {
+ const url = new URL(`admin/add-kycauth`, this.baseUrl);
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ headers: {
+ Authorization: makeBasicAuthHeader(this.username, auth),
+ },
+ body,
+ });
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForAddIncomingResponse());
+ //FIXME: show more details in docs
+ case HttpStatusCode.BadRequest:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Unauthorized:
+ return opKnownHttpFailure(resp.status, resp);
+ //FIXME: show more details in docs
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+ }
+ }
}
diff --git a/packages/taler-util/src/http-client/challenger.ts b/packages/taler-util/src/http-client/challenger.ts
index 1b0fda300..1c6f54be2 100644
--- a/packages/taler-util/src/http-client/challenger.ts
+++ b/packages/taler-util/src/http-client/challenger.ts
@@ -63,7 +63,7 @@ export enum ChallengerCacheEviction {
export class ChallengerHttpClient {
httpLib: HttpRequestLibrary;
cacheEvictor: CacheEvictor<ChallengerCacheEviction>;
- public readonly PROTOCOL_VERSION = "1:0:0";
+ public readonly PROTOCOL_VERSION = "2:0:0";
constructor(
readonly baseUrl: string,
diff --git a/packages/taler-util/src/http-client/exchange.ts b/packages/taler-util/src/http-client/exchange.ts
index 9b7635cb4..7526fd8a0 100644
--- a/packages/taler-util/src/http-client/exchange.ts
+++ b/packages/taler-util/src/http-client/exchange.ts
@@ -1,3 +1,19 @@
+/*
+ This file is part of GNU Taler
+ (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
+ 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/>
+ */
+
import {
HttpRequestLibrary,
readSuccessResponseJsonOrThrow,
@@ -17,16 +33,18 @@ import {
opKnownAlternativeFailure,
opKnownHttpFailure,
opSuccessFromHttp,
- opUnknownFailure
+ opUnknownFailure,
} from "../operation.js";
+import { Codec, codecForAny } from "../codec.js";
import {
TalerSignaturePurpose,
+ bufferForUint64,
buildSigPS,
decodeCrock,
eddsaSign,
encodeCrock,
stringToBytes,
- timestampRoundedToBuffer
+ timestampRoundedToBuffer,
} from "../taler-crypto.js";
import {
AccessToken,
@@ -35,10 +53,12 @@ import {
PaginationParams,
ReserveAccount,
SigningKey,
- codecForTalerCommonConfigResponse
+ codecForTalerCommonConfigResponse,
} from "../types-taler-common.js";
import {
AmlDecisionRequest,
+ BatchWithdrawResponse,
+ ExchangeBatchWithdrawRequest,
ExchangeVersionResponse,
KycRequirementInformationId,
WalletKycRequest,
@@ -52,13 +72,14 @@ import {
codecForExchangeKeys,
codecForKycProcessClientInformation,
codecForKycProcessStartInformation,
- codecForLegitimizationNeededResponse
+ codecForLegitimizationNeededResponse,
} from "../types-taler-exchange.js";
-import { CacheEvictor, addMerchantPaginationParams, nullEvictor } from "./utils.js";
+import { CacheEvictor, addPaginationParams, nullEvictor } from "./utils.js";
import { TalerError } from "../errors.js";
import { TalerErrorCode } from "../taler-error-codes.js";
import { codecForEmptyObject } from "../types-taler-wallet.js";
+import { canonicalJson } from "../helpers.js";
export type TalerExchangeResultByMethod<
prop extends keyof TalerExchangeHttpClient,
@@ -68,14 +89,17 @@ export type TalerExchangeErrorsByMethod<
> = FailCasesByMethod<TalerExchangeHttpClient, prop>;
export enum TalerExchangeCacheEviction {
- CREATE_DESCISION,
+ UPLOAD_KYC_FORM,
+ MAKE_AML_DECISION,
}
+declare const __pubId: unique symbol;
+export type ReservePub = string & { [__pubId]: true };
/**
*/
export class TalerExchangeHttpClient {
httpLib: HttpRequestLibrary;
- public readonly PROTOCOL_VERSION = "20:0:0";
+ public readonly PROTOCOL_VERSION = "21:0:0";
cacheEvictor: CacheEvictor<TalerExchangeCacheEviction>;
constructor(
@@ -91,6 +115,20 @@ export class TalerExchangeHttpClient {
const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version);
return compare?.compatible ?? false;
}
+
+ // TERMS
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--seed
+ *
+ */
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--seed
+ *
+ */
+
+ // EXCHANGE INFORMATION
+
/**
* https://docs.taler.net/core/api-exchange.html#get--seed
*
@@ -163,6 +201,7 @@ export class TalerExchangeHttpClient {
return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
+
/**
* https://docs.taler.net/core/api-merchant.html#get--config
*
@@ -181,10 +220,390 @@ export class TalerExchangeHttpClient {
}
}
- // TERMS
+ //
+ // MANAGEMENT
+ //
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--management-keys
+ *
+ */
+ async getFutureKeys(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--management-keys
+ *
+ */
+ async signFutureKeys(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--management-denominations-$H_DENOM_PUB-revoke
+ *
+ */
+ async revokeFutureDenominationKeys(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--management-signkeys-$EXCHANGE_PUB-revoke
+ *
+ */
+ async revokeFutureSigningKeys(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--management-auditors
+ *
+ */
+ async enableAuditor(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--management-auditors-$AUDITOR_PUB-disable
+ *
+ */
+ async disableAuditor(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--management-wire-fee
+ *
+ */
+ async configWireFee(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--management-global-fees
+ *
+ */
+ async configGlobalFees(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--management-wire
+ *
+ */
+ async enableWireMethod(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--management-wire-disable
+ *
+ */
+ async disableWireMethod(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--management-drain
+ *
+ */
+ async drainProfits(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--management-aml-officers
+ *
+ */
+ async updateOfficer(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--management-partners
+ *
+ */
+ async enablePartner(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ //
+ // AUDITOR
+ //
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--auditors-$AUDITOR_PUB-$H_DENOM_PUB
+ *
+ */
+ async addAuditor(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ //
+ // WITHDRAWAL
+ //
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--reserves-$RESERVE_PUB
+ *
+ */
+ async getReserveInfo(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--csr-withdraw
+ *
+ */
+ async prepareCsrWithdawal(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--reserves-$RESERVE_PUB-batch-withdraw
+ *
+ */
+ async withdraw(rid: ReservePub, body: ExchangeBatchWithdrawRequest) {
+ const url = new URL(`reserves/${rid}/batch-withdraw`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "POST",
+ body,
+ });
+
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(
+ resp,
+ codecForAny() as Codec<BatchWithdrawResponse>,
+ );
+ case HttpStatusCode.Forbidden:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.BadRequest:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Conflict:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.Gone:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.UnavailableForLegalReasons:
+ return opKnownAlternativeFailure(
+ resp,
+ resp.status,
+ codecForLegitimizationNeededResponse(),
+ );
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+ }
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#withdraw-with-age-restriction
+ *
+ */
+ async withdrawWithAge(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--age-withdraw-$ACH-reveal
+ *
+ */
+ async revealCoinsForAge(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ //
+ // RESERVE HISTORY
+ //
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--reserves-$RESERVE_PUB-history
+ *
+ */
+ async getResverveHistory(): Promise<never> {
+ throw Error("not yet implemented");
+ }
//
- // KYC operations
+ // COIN HISTORY
+ //
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--coins-$COIN_PUB-history
+ *
+ */
+ async getCoinHistory(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ //
+ // DEPOSIT
+ //
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--batch-deposit
+ *
+ */
+ async deposit(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ //
+ // REFRESH
+ //
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--csr-melt
+ *
+ */
+ async prepareCsrMelt(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--coins-$COIN_PUB-melt
+ *
+ */
+ async meltCoin(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--refreshes-$RCH-reveal
+ *
+ */
+ async releaveCoin(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--coins-$COIN_PUB-link
+ *
+ */
+ async linkCoin(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ //
+ // RECOUP
+ //
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--coins-$COIN_PUB-recoup
+ *
+ */
+ async recoupReserveCoin(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--coins-$COIN_PUB-recoup-refresh
+ *
+ */
+ async recoupRefreshCoin(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ // WIRE TRANSFER
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--transfers-$WTID
+ *
+ */
+ async getWireTransferInfo(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--deposits-$H_WIRE-$MERCHANT_PUB-$H_CONTRACT_TERMS-$COIN_PUB
+ *
+ */
+ async getWireTransferIdForDeposit(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ // REFUND
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--coins-$COIN_PUB-refund
+ *
+ */
+ async refund(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ // WALLET TO WALLET
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--purses-$PURSE_PUB-merge
+ *
+ */
+ async getPurseInfoAtMerge(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--purses-$PURSE_PUB-deposit
+ *
+ */
+ async getPurseInfoAtDeposit(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--purses-$PURSE_PUB-create
+ *
+ */
+ async createPurseFromDeposit(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#delete--purses-$PURSE_PUB
+ *
+ */
+ async deletePurse(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--purses-$PURSE_PUB-merge
+ *
+ */
+ async mergePurse(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--reserves-$RESERVE_PUB-purse
+ *
+ */
+ async createPurseFromReserve(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--purses-$PURSE_PUB-deposit
+ *
+ */
+ async depositIntoPurse(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ // WADS
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--wads-$WAD_ID
+ *
+ */
+ async getWadInfo(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ //
+ // KYC
//
/**
@@ -198,7 +617,7 @@ export class TalerExchangeHttpClient {
balance,
reserve_pub: account.id,
reserve_sig: encodeCrock(account.signingKey),
- }
+ };
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
@@ -213,29 +632,41 @@ export class TalerExchangeHttpClient {
case HttpStatusCode.Forbidden:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.UnavailableForLegalReasons:
- return opKnownAlternativeFailure(resp, resp.status, codecForLegitimizationNeededResponse());
+ return opKnownAlternativeFailure(
+ resp,
+ resp.status,
+ codecForLegitimizationNeededResponse(),
+ );
default:
return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
}
/**
- * https://docs.taler.net/core/api-exchange.html#post--kyc-wallet
+ * https://docs.taler.net/core/api-exchange.html#get--kyc-check-$H_PAYTO
*
*/
- async checkKycStatus(account: ReserveAccount, requirementId: number, params: {
- timeout?: number,
- } = {}) {
- const url = new URL(`kyc-check/${String(requirementId)}`, this.baseUrl);
+ async checkKycStatus(
+ signingKey: SigningKey,
+ paytoHash: string,
+ params: {
+ timeout?: number;
+ awaitAuth?: boolean;
+ } = {},
+ ) {
+ const url = new URL(`kyc-check/${paytoHash}`, this.baseUrl);
if (params.timeout !== undefined) {
url.searchParams.set("timeout_ms", String(params.timeout));
}
+ if (params.awaitAuth !== undefined) {
+ url.searchParams.set("await_auth", params.awaitAuth ? "YES" : "NO");
+ }
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- "Account-Owner-Signature": buildKYCQuerySignature(account.signingKey),
+ "Account-Owner-Signature": buildKYCQuerySignature(signingKey),
},
});
@@ -243,9 +674,9 @@ export class TalerExchangeHttpClient {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForAccountKycStatus());
case HttpStatusCode.Accepted:
- return opKnownAlternativeFailure(resp, resp.status, codecForAccountKycStatus());
+ return opSuccessFromHttp(resp, codecForAccountKycStatus());
case HttpStatusCode.NoContent:
- return opEmptySuccess(resp);
+ return opFixedSuccess(undefined);
case HttpStatusCode.Forbidden:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
@@ -258,12 +689,16 @@ export class TalerExchangeHttpClient {
}
/**
- * https://docs.taler.net/core/api-exchange.html#get--kyc-info-$ACCESS_TOKEN
- *
- */
- async checkKycInfo(token: AccessToken, known: KycRequirementInformationId[], params: {
- timeout?: number,
- } = {}) {
+ * https://docs.taler.net/core/api-exchange.html#get--kyc-info-$ACCESS_TOKEN
+ *
+ */
+ async checkKycInfo(
+ token: AccessToken,
+ known: KycRequirementInformationId[],
+ params: {
+ timeout?: number;
+ } = {},
+ ) {
const url = new URL(`kyc-info/${token}`, this.baseUrl);
if (params.timeout !== undefined) {
@@ -273,15 +708,25 @@ export class TalerExchangeHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- "If-None-Match": known.length ? known.join(",") : undefined
- }
+ "If-None-Match": known.length ? known.join(",") : undefined,
+ },
});
switch (resp.status) {
case HttpStatusCode.Ok:
return opSuccessFromHttp(resp, codecForKycProcessClientInformation());
+ case HttpStatusCode.Accepted:
+ return opKnownAlternativeFailure(
+ resp,
+ HttpStatusCode.Accepted,
+ codecForEmptyObject(),
+ );
case HttpStatusCode.NoContent:
- return opKnownAlternativeFailure(resp, HttpStatusCode.NoContent, codecForEmptyObject());
+ return opKnownAlternativeFailure(
+ resp,
+ HttpStatusCode.NoContent,
+ codecForEmptyObject(),
+ );
case HttpStatusCode.NotModified:
return opKnownHttpFailure(resp.status, resp);
default:
@@ -289,7 +734,6 @@ export class TalerExchangeHttpClient {
}
}
-
/**
* https://docs.taler.net/core/api-exchange.html#post--kyc-upload-$ID
*
@@ -303,8 +747,12 @@ export class TalerExchangeHttpClient {
});
switch (resp.status) {
- case HttpStatusCode.NoContent:
+ case HttpStatusCode.NoContent: {
+ this.cacheEvictor.notifySuccess(
+ TalerExchangeCacheEviction.UPLOAD_KYC_FORM,
+ );
return opEmptySuccess(resp);
+ }
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict:
@@ -320,13 +768,15 @@ export class TalerExchangeHttpClient {
* https://docs.taler.net/core/api-exchange.html#post--kyc-start-$ID
*
*/
- async startKycProcess(requirement: KycRequirementInformationId, body: object = {}) {
+ async startExternalKycProcess(
+ requirement: KycRequirementInformationId,
+ body: object = {},
+ ) {
const url = new URL(`kyc-start/${requirement}`, this.baseUrl);
-
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
- body
+ body,
});
switch (resp.status) {
@@ -343,119 +793,40 @@ export class TalerExchangeHttpClient {
}
}
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--kyc-proof-$PROVIDER_NAME?state=$H_PAYTO
+ *
+ */
+ async completeExternalKycProcess(
+ provider: string,
+ state: string,
+ code: string,
+ ) {
+ const url = new URL(
+ `kyc-proof/${provider}?state=${state}&code=${code}`,
+ this.baseUrl,
+ );
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "GET",
+ redirect: "manual",
+ });
+
+ switch (resp.status) {
+ case HttpStatusCode.SeeOther:
+ return opEmptySuccess(resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await readTalerErrorResponse(resp));
+ }
+ }
+
//
// AML operations
//
/**
- * https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-decisions-$STATE
- *
- */
- // async getDecisionsByState(
- // auth: OfficerAccount,
- // state: TalerExchangeApi.AmlState,
- // pagination?: PaginationParams,
- // ) {
- // const url = new URL(
- // `aml/${auth.id}/decisions/${TalerExchangeApi.AmlState[state]}`,
- // this.baseUrl,
- // );
- // addPaginationParams(url, pagination);
-
- // const resp = await this.httpLib.fetch(url.href, {
- // method: "GET",
- // headers: {
- // "Taler-AML-Officer-Signature": buildQuerySignature(auth.signingKey),
- // },
- // });
-
- // switch (resp.status) {
- // case HttpStatusCode.Ok:
- // return opSuccessFromHttp(resp, codecForAmlRecords());
- // case HttpStatusCode.NoContent:
- // return opFixedSuccess({ records: [] });
- // //this should be unauthorized
- // case HttpStatusCode.Forbidden:
- // return opKnownHttpFailure(resp.status, resp);
- // case HttpStatusCode.Unauthorized:
- // 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-exchange.html#get--aml-$OFFICER_PUB-decision-$H_PAYTO
- // *
- // */
- // async getDecisionDetails(auth: OfficerAccount, account: string) {
- // const url = new URL(`aml/${auth.id}/decision/${account}`, this.baseUrl);
-
- // const resp = await this.httpLib.fetch(url.href, {
- // method: "GET",
- // headers: {
- // "Taler-AML-Officer-Signature": buildQuerySignature(auth.signingKey),
- // },
- // });
-
- // switch (resp.status) {
- // case HttpStatusCode.Ok:
- // return opSuccessFromHttp(resp, codecForAmlDecisionDetails());
- // case HttpStatusCode.NoContent:
- // return opFixedSuccess({ aml_history: [], kyc_attributes: [] });
- // //this should be unauthorized
- // case HttpStatusCode.Forbidden:
- // return opKnownHttpFailure(resp.status, resp);
- // case HttpStatusCode.Unauthorized:
- // 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-exchange.html#post--aml-$OFFICER_PUB-decision
- // *
- // */
- // async addDecisionDetails(
- // auth: OfficerAccount,
- // decision: Omit<TalerExchangeApi.AmlDecision, "officer_sig">,
- // ) {
- // const url = new URL(`aml/${auth.id}/decision`, this.baseUrl);
-
- // const body = buildDecisionSignature(auth.signingKey, decision);
- // const resp = await this.httpLib.fetch(url.href, {
- // method: "POST",
- // body,
- // });
-
- // switch (resp.status) {
- // case HttpStatusCode.NoContent:
- // return opEmptySuccess(resp);
- // //FIXME: this should be unauthorized
- // case HttpStatusCode.Forbidden:
- // return opKnownHttpFailure(resp.status, resp);
- // case HttpStatusCode.Unauthorized:
- // return opKnownHttpFailure(resp.status, resp);
- // //FIXME: this two need to be split by error code
- // 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-exchange.html#get--aml-$OFFICER_PUB-measures
*
*/
@@ -481,26 +852,23 @@ export class TalerExchangeHttpClient {
* https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-measures
*
*/
- async getAmlKycStatistics(auth: OfficerAccount, name: string, filter: {
- since?: Date
- until?: Date
- } = {}) {
+ async getAmlKycStatistics(
+ auth: OfficerAccount,
+ name: string,
+ filter: {
+ since?: Date;
+ until?: Date;
+ } = {},
+ ) {
const url = new URL(`aml/${auth.id}/kyc-statistics/${name}`, this.baseUrl);
if (filter.since !== undefined) {
- url.searchParams.set(
- "start_date",
- String(filter.since.getTime())
- );
+ url.searchParams.set("start_date", String(filter.since.getTime()));
}
if (filter.until !== undefined) {
- url.searchParams.set(
- "end_date",
- String(filter.until.getTime())
- );
+ url.searchParams.set("end_date", String(filter.until.getTime()));
}
-
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
@@ -519,14 +887,17 @@ export class TalerExchangeHttpClient {
* https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-decisions
*
*/
- async getAmlDecisions(auth: OfficerAccount, params: PaginationParams & {
- account?: string,
- active?: boolean,
- investigation?: boolean,
- } = {}) {
+ async getAmlDecisions(
+ auth: OfficerAccount,
+ params: PaginationParams & {
+ account?: string;
+ active?: boolean;
+ investigation?: boolean;
+ } = {},
+ ) {
const url = new URL(`aml/${auth.id}/decisions`, this.baseUrl);
- addMerchantPaginationParams(url, params);
+ addPaginationParams(url, params);
if (params.account !== undefined) {
url.searchParams.set("h_payto", params.account);
}
@@ -534,7 +905,10 @@ export class TalerExchangeHttpClient {
url.searchParams.set("active", params.active ? "YES" : "NO");
}
if (params.investigation !== undefined) {
- url.searchParams.set("investigation", params.investigation ? "YES" : "NO");
+ url.searchParams.set(
+ "investigation",
+ params.investigation ? "YES" : "NO",
+ );
}
const resp = await this.httpLib.fetch(url.href, {
@@ -564,10 +938,14 @@ export class TalerExchangeHttpClient {
* https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-attributes-$H_PAYTO
*
*/
- async getAmlAttributesForAccount(auth: OfficerAccount, account: string, params: PaginationParams = {}) {
+ async getAmlAttributesForAccount(
+ auth: OfficerAccount,
+ account: string,
+ params: PaginationParams = {},
+ ) {
const url = new URL(`aml/${auth.id}/attributes/${account}`, this.baseUrl);
- addMerchantPaginationParams(url, params);
+ addPaginationParams(url, params);
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
@@ -591,12 +969,14 @@ export class TalerExchangeHttpClient {
}
}
-
/**
* https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-attributes-$H_PAYTO
*
*/
- async makeAmlDesicion(auth: OfficerAccount, decision: Omit<AmlDecisionRequest, "officer_sig">) {
+ async makeAmlDesicion(
+ auth: OfficerAccount,
+ decision: Omit<AmlDecisionRequest, "officer_sig">,
+ ) {
const url = new URL(`aml/${auth.id}/decision`, this.baseUrl);
const body = buildAMLDecisionSignature(auth.signingKey, decision);
@@ -609,8 +989,12 @@ export class TalerExchangeHttpClient {
});
switch (resp.status) {
- case HttpStatusCode.NoContent:
+ case HttpStatusCode.NoContent: {
+ this.cacheEvictor.notifySuccess(
+ TalerExchangeCacheEviction.MAKE_AML_DECISION,
+ );
return opEmptySuccess(resp);
+ }
case HttpStatusCode.Forbidden:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
@@ -622,20 +1006,57 @@ export class TalerExchangeHttpClient {
}
}
+ // RESERVE control
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--reserves-$RESERVE_PUB-open
+ *
+ */
+ async reserveOpen(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#get--reserves-attest-$RESERVE_PUB
+ *
+ */
+ async getReserveAttributes(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--reserves-attest-$RESERVE_PUB
+ *
+ */
+ async signReserveAttributes(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#post--reserves-$RESERVE_PUB-close
+ *
+ */
+ async closeReserve(): Promise<never> {
+ throw Error("not yet implemented");
+ }
+
+ /**
+ * https://docs.taler.net/core/api-exchange.html#delete--reserves-$RESERVE_PUB
+ *
+ */
+ async deleteReserve(): Promise<never> {
+ throw Error("not yet implemented");
+ }
}
function buildKYCQuerySignature(key: SigningKey): string {
- const sigBlob = buildSigPS(
- TalerSignaturePurpose.AML_QUERY,
- ).build();
+ const sigBlob = buildSigPS(TalerSignaturePurpose.KYC_AUTH).build();
return encodeCrock(eddsaSign(sigBlob, key));
}
function buildAMLQuerySignature(key: SigningKey): string {
- const sigBlob = buildSigPS(
- TalerSignaturePurpose.AML_QUERY,
- ).build();
+ const sigBlob = buildSigPS(TalerSignaturePurpose.AML_QUERY).build();
return encodeCrock(eddsaSign(sigBlob, key));
}
@@ -647,16 +1068,21 @@ function buildAMLDecisionSignature(
const zero = new Uint8Array(new ArrayBuffer(64));
const sigBlob = buildSigPS(TalerSignaturePurpose.AML_DECISION)
- //TODO: new need the null terminator, also in the exchange
- .put(hash(stringToBytes(decision.justification))) //check null
.put(timestampRoundedToBuffer(decision.decision_time))
- // .put(amountToBuffer(decision.new_threshold))
.put(decodeCrock(decision.h_payto))
- .put(zero) //kyc_requirement
- // .put(bufferForUint32(decision.new_state))
+ .put(hash(stringToBytes(decision.justification)))
+ .put(hash(stringToBytes(canonicalJson(decision.properties) + "\0")))
+ .put(hash(stringToBytes(canonicalJson(decision.new_rules) + "\0")))
+ .put(
+ decision.new_measures != null
+ ? hash(stringToBytes(decision.new_measures))
+ : zero,
+ )
+ .put(bufferForUint64(decision.keep_investigating ? 1 : 0))
.build();
const officer_sig = encodeCrock(eddsaSign(sigBlob, key));
+
return {
...decision,
officer_sig,
diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts
index e765d286b..e6af6dfe8 100644
--- a/packages/taler-util/src/http-client/merchant.ts
+++ b/packages/taler-util/src/http-client/merchant.ts
@@ -45,6 +45,7 @@ import {
codecForOtpDeviceSummaryResponse,
codecForOutOfStockResponse,
codecForPaidRefundStatusResponse,
+ codecForPaymentDeniedLegallyResponse,
codecForPaymentResponse,
codecForPostOrderResponse,
codecForProductDetail,
@@ -76,8 +77,8 @@ import {
} from "@gnu-taler/taler-util/http";
import { opSuccessFromHttp, opUnknownFailure } from "../operation.js";
import {
+ addPaginationParams,
CacheEvictor,
- addMerchantPaginationParams,
makeBearerTokenAuthHeader,
nullEvictor,
} from "./utils.js";
@@ -137,7 +138,7 @@ export enum TalerMerchantManagementCacheEviction {
* Uses libtool's current:revision:age versioning.
*/
export class TalerMerchantInstanceHttpClient {
- public readonly PROTOCOL_VERSION = "16:0:0";
+ public readonly PROTOCOL_VERSION = "17:0:1";
readonly httpLib: HttpRequestLibrary;
readonly cacheEvictor: CacheEvictor<TalerMerchantInstanceCacheEviction>;
@@ -276,6 +277,12 @@ export class TalerMerchantInstanceHttpClient {
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.GatewayTimeout:
return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.UnavailableForLegalReasons:
+ return opKnownAlternativeFailure(
+ resp,
+ resp.status,
+ codecForPaymentDeniedLegallyResponse(),
+ );
default:
return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
@@ -431,6 +438,12 @@ export class TalerMerchantInstanceHttpClient {
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.UnavailableForLegalReasons:
+ return opKnownAlternativeFailure(
+ resp,
+ resp.status,
+ codecForPaymentDeniedLegallyResponse(),
+ );
default:
return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
@@ -604,6 +617,8 @@ export class TalerMerchantInstanceHttpClient {
});
switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForAccountKycRedirects());
case HttpStatusCode.Accepted:
return opSuccessFromHttp(resp, codecForAccountKycRedirects());
case HttpStatusCode.NoContent:
@@ -712,7 +727,7 @@ export class TalerMerchantInstanceHttpClient {
) {
const url = new URL(`private/accounts`, this.baseUrl);
- // addMerchantPaginationParams(url, params);
+ // addPaginationParams(url, params);
const headers: Record<string, string> = {};
if (token) {
@@ -809,7 +824,7 @@ export class TalerMerchantInstanceHttpClient {
) {
const url = new URL(`private/categories`, this.baseUrl);
- // addMerchantPaginationParams(url, params);
+ // addPaginationParams(url, params);
const headers: Record<string, string> = {};
if (token) {
@@ -1051,7 +1066,7 @@ export class TalerMerchantInstanceHttpClient {
) {
const url = new URL(`private/products`, this.baseUrl);
- addMerchantPaginationParams(url, params);
+ addPaginationParams(url, params);
const headers: Record<string, string> = {};
if (token) {
@@ -1234,6 +1249,12 @@ export class TalerMerchantInstanceHttpClient {
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Unauthorized: // FIXME: missing in docs
return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.UnavailableForLegalReasons:
+ return opKnownAlternativeFailure(
+ resp,
+ resp.status,
+ codecForPaymentDeniedLegallyResponse(),
+ );
case HttpStatusCode.Conflict:
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Gone:
@@ -1277,7 +1298,7 @@ export class TalerMerchantInstanceHttpClient {
if (params.wired !== undefined) {
url.searchParams.set("wired", params.wired ? "YES" : "NO");
}
- addMerchantPaginationParams(url, params);
+ addPaginationParams(url, params);
const headers: Record<string, string> = {};
if (token) {
@@ -1471,6 +1492,12 @@ export class TalerMerchantInstanceHttpClient {
return opKnownHttpFailure(resp.status, resp);
case HttpStatusCode.Conflict:
return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.UnavailableForLegalReasons:
+ return opKnownAlternativeFailure(
+ resp,
+ resp.status,
+ codecForPaymentDeniedLegallyResponse(),
+ );
default:
return opUnknownFailure(resp, await readTalerErrorResponse(resp));
}
@@ -1538,7 +1565,7 @@ export class TalerMerchantInstanceHttpClient {
if (params.verified !== undefined) {
url.searchParams.set("verified", params.verified ? "YES" : "NO");
}
- addMerchantPaginationParams(url, params);
+ addPaginationParams(url, params);
const headers: Record<string, string> = {};
if (token) {
@@ -1679,7 +1706,7 @@ export class TalerMerchantInstanceHttpClient {
) {
const url = new URL(`private/otp-devices`, this.baseUrl);
- addMerchantPaginationParams(url, params);
+ addPaginationParams(url, params);
const headers: Record<string, string> = {};
if (token) {
@@ -1852,7 +1879,7 @@ export class TalerMerchantInstanceHttpClient {
) {
const url = new URL(`private/templates`, this.baseUrl);
- addMerchantPaginationParams(url, params);
+ addPaginationParams(url, params);
const headers: Record<string, string> = {};
if (token) {
@@ -2584,3 +2611,29 @@ export class TalerMerchantManagementHttpClient extends TalerMerchantInstanceHttp
}
}
}
+
+// 2024-09-23T01:23:14.421Z http.ts INFO malformed error response (status 200): {
+// "kyc_data": [
+// {
+// "payto_uri": "payto://iban/DE1327812254798?receiver-name=the%20name%20of%20merchant",
+// "exchange_url": "http://exchange.taler.test:1180/",
+// "no_keys": false,
+// "auth_conflict": false,
+// "exchange_http_status": 204,
+// "limits": [],
+// "payto_kycauths": [
+// "payto://iban/DE9714548806481?receiver-name=Exchanger+Normal&subject=54DR9R0CEWA1A7FK3QWABJ1PRBCD2X6S418Y5DE0P9Q1ASKTX770"
+// ]
+// },
+// {
+// "payto_uri": "payto://iban/DE1327812254798?receiver-name=the%20name%20of%20merchant",
+// "exchange_url": "https://exchange.demo.taler.net/",
+// "no_keys": false,
+// "auth_conflict": false,
+// "exchange_http_status": 400,
+// "exchange_code": 26,
+// "access_token": "0000000000000000000000000000000000000000000000000000",
+// "limits": []
+// }
+// ]
+// }
diff --git a/packages/taler-util/src/http-client/officer-account.ts b/packages/taler-util/src/http-client/officer-account.ts
index 612fd815e..f5f55ea1b 100644
--- a/packages/taler-util/src/http-client/officer-account.ts
+++ b/packages/taler-util/src/http-client/officer-account.ts
@@ -17,11 +17,8 @@
import {
EncryptionNonce,
LockedAccount,
- LockedReserve,
OfficerAccount,
OfficerId,
- ReserveAccount,
- ReserveId,
SigningKey,
createEddsaKeyPair,
decodeCrock,
@@ -31,7 +28,7 @@ import {
encryptWithDerivedKey,
getRandomBytesF,
kdf,
- stringToBytes,
+ stringToBytes
} from "@gnu-taler/taler-util";
/**
@@ -100,36 +97,6 @@ export async function createNewOfficerAccount(
}
/**
- * Restore previous session and unlock account with password
- *
- * @param salt string from which crypto params will be derived
- * @param key secured private key
- * @param password password for the private key
- * @returns
- */
-export async function unlockWalletKycAccount(
- account: LockedReserve,
- password: string,
-): Promise<ReserveAccount> {
- const rawKey = decodeCrock(account);
- const rawPassword = stringToBytes(password);
-
- const signingKey = (await decryptWithDerivedKey(
- rawKey,
- rawPassword,
- password,
- ).catch((e) => {
- throw new UnwrapKeyError(e instanceof Error ? e.message : String(e));
- })) as SigningKey;
-
- const publicKey = eddsaGetPublic(signingKey);
-
- const accountId = encodeCrock(publicKey) as ReserveId;
-
- return { id: accountId, signingKey };
-}
-
-/**
* Create new account (secured private key)
* secured with the given password
*
diff --git a/packages/taler-util/src/http-client/utils.ts b/packages/taler-util/src/http-client/utils.ts
index baea3ce6f..a69eb0847 100644
--- a/packages/taler-util/src/http-client/utils.ts
+++ b/packages/taler-util/src/http-client/utils.ts
@@ -46,29 +46,38 @@ export function makeBearerTokenAuthHeader(token: AccessToken): string {
return `Bearer ${token}`;
}
+export type BasicOrTokenAuth = BasicAuth | TokenAuth;
+
+export type BasicAuth = {
+ type: "basic";
+ username: string;
+ password: string;
+};
+
+export type TokenAuth = {
+ type: "bearer";
+ token: AccessToken;
+};
+
+export function createAuthorizationHeader(auth?: BasicOrTokenAuth): string | undefined {
+ if (!auth) return undefined;
+ switch (auth.type) {
+ case "basic": {
+ return makeBasicAuthHeader(auth.username, auth.password);
+ }
+ case "bearer": {
+ return makeBearerTokenAuthHeader(auth.token);
+ }
+ }
+ return undefined;
+}
+
/**
* https://bugs.gnunet.org/view.php?id=7949
*/
export function addPaginationParams(url: URL, pagination?: PaginationParams) {
if (!pagination) return;
if (pagination.offset) {
- url.searchParams.set("start", pagination.offset);
- }
- const order = !pagination || pagination.order === "asc" ? 1 : -1;
- const limit =
- !pagination || !pagination.limit || pagination.limit === 0
- ? 5
- : Math.abs(pagination.limit);
- //always send delta
- url.searchParams.set("delta", String(order * limit));
-}
-
-export function addMerchantPaginationParams(
- url: URL,
- pagination?: PaginationParams,
-) {
- if (!pagination) return;
- if (pagination.offset) {
url.searchParams.set("offset", pagination.offset);
}
const order = !pagination || pagination.order === "asc" ? 1 : -1;
@@ -76,14 +85,14 @@ export function addMerchantPaginationParams(
!pagination || !pagination.limit || pagination.limit === 0
? 5
: Math.abs(pagination.limit);
- //always send delta
+ //always send limit
url.searchParams.set("limit", String(order * limit));
}
export function addLongPollingParam(url: URL, param?: LongPollParams) {
if (!param) return;
if (param.timeoutMs) {
- url.searchParams.set("long_poll_ms", String(param.timeoutMs));
+ url.searchParams.set("timeout_ms", String(param.timeoutMs));
}
}
@@ -95,26 +104,3 @@ export const nullEvictor: CacheEvictor<unknown> = {
notifySuccess: () => Promise.resolve(),
};
-export class IdempotencyRetry {
- public readonly uid: string;
- public readonly timesLeft: number;
- public readonly maxTries: number;
-
- private constructor(timesLeft: number, maxTimesLeft: number) {
- this.timesLeft = timesLeft;
- this.maxTries = maxTimesLeft;
- this.uid = encodeCrock(getRandomBytes(32));
- }
-
- static tryFiveTimes() {
- return new IdempotencyRetry(5, 5);
- }
-
- next(): IdempotencyRetry | undefined {
- const left = this.timesLeft - 1;
- if (left <= 0) {
- return undefined;
- }
- return new IdempotencyRetry(left, this.maxTries);
- }
-}