[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-typescript-core] branch master updated: unify diverged exchange c
From: |
Admin |
Subject: |
[taler-typescript-core] branch master updated: unify diverged exchange clients |
Date: |
Thu, 05 Jun 2025 02:22:38 +0200 |
This is an automated email from the git hooks/post-receive script.
dold pushed a commit to branch master
in repository taler-typescript-core.
The following commit(s) were added to refs/heads/master by this push:
new 6eee7ef19 unify diverged exchange clients
6eee7ef19 is described below
commit 6eee7ef1967d69875684f7d80d79c8cdd5a912f4
Author: Florian Dold <florian@dold.me>
AuthorDate: Thu Jun 5 02:21:45 2025 +0200
unify diverged exchange clients
Issue: https://bugs.taler.net/n/10049
---
packages/aml-backoffice-ui/src/App.tsx | 14 +-
packages/aml-backoffice-ui/src/hooks/account.ts | 4 +-
packages/aml-backoffice-ui/src/hooks/decisions.ts | 12 +-
.../aml-backoffice-ui/src/hooks/server-info.ts | 9 +-
packages/aml-backoffice-ui/src/hooks/transfers.ts | 8 +-
.../aml-backoffice-ui/src/pages/CaseDetails.tsx | 6 +-
packages/aml-backoffice-ui/src/pages/Search.tsx | 7 +-
.../src/pages/ShowCollectedInfo.tsx | 1 -
packages/aml-backoffice-ui/src/pages/Transfers.tsx | 27 +-
.../aml-backoffice-ui/src/pages/decision/Rules.tsx | 168 ++--
packages/bank-ui/src/hooks/account.ts | 7 +-
packages/kyc-ui/src/hooks/kyc.ts | 8 +-
packages/kyc-ui/src/pages/FillForm.tsx | 22 +-
packages/taler-harness/src/harness/environments.ts | 6 +-
packages/taler-harness/src/harness/tops.ts | 9 +-
.../integrationtests/test-withdrawal-idempotent.ts | 4 +-
packages/taler-util/src/aml/reporting.ts | 42 +-
.../taler-util/src/http-client/exchange-client.ts | 137 ++-
packages/taler-util/src/http-client/exchange.ts | 1001 --------------------
.../taler-util/src/http-client/officer-account.ts | 31 +-
packages/taler-util/src/index.ts | 1 -
packages/taler-util/src/types-taler-common.ts | 26 +-
packages/taler-util/src/types-taler-exchange.ts | 3 +
packages/taler-wallet-core/src/dbless.ts | 6 +-
packages/taler-wallet-core/src/versions.ts | 4 +-
packages/taler-wallet-core/src/wallet.ts | 6 +-
packages/web-util/src/context/exchange-api.ts | 2 +-
packages/web-util/src/hooks/useAsync.ts | 8 +-
28 files changed, 318 insertions(+), 1261 deletions(-)
diff --git a/packages/aml-backoffice-ui/src/App.tsx
b/packages/aml-backoffice-ui/src/App.tsx
index cb9abd800..6b0efd2a5 100644
--- a/packages/aml-backoffice-ui/src/App.tsx
+++ b/packages/aml-backoffice-ui/src/App.tsx
@@ -24,21 +24,23 @@ import {
ExchangeApiProvider,
Loading,
TranslationProvider,
- UiForms,
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
import { useEffect, useState } from "preact/hooks";
import { SWRConfig } from "swr";
import { ExchangeAmlFrame } from "./ExchangeAmlFrame.js";
import { Routing } from "./Routing.js";
-import { UiSettingsProvider } from "./context/ui-settings.js";
-import { strings } from "./i18n/strings.js";
-import "./scss/main.css";
-import { UiSettings, fetchUiSettings } from "./context/ui-settings.js";
import { UiFormsProvider } from "./context/ui-forms.js";
-import { revalidateAccountDecisions } from "./hooks/decisions.js";
+import {
+ UiSettings,
+ UiSettingsProvider,
+ fetchUiSettings,
+} from "./context/ui-settings.js";
import { revalidateAccountInformation } from "./hooks/account.js";
+import { revalidateAccountDecisions } from "./hooks/decisions.js";
import { usePreferences } from "./hooks/preferences.js";
+import { strings } from "./i18n/strings.js";
+import "./scss/main.css";
const WITH_LOCAL_STORAGE_CACHE = false;
diff --git a/packages/aml-backoffice-ui/src/hooks/account.ts
b/packages/aml-backoffice-ui/src/hooks/account.ts
index f34da0825..b71a70c85 100644
--- a/packages/aml-backoffice-ui/src/hooks/account.ts
+++ b/packages/aml-backoffice-ui/src/hooks/account.ts
@@ -16,7 +16,7 @@
import {
OfficerAccount,
PaytoString,
- TalerExchangeResultByMethod,
+ TalerExchangeResultByMethod2,
TalerHttpError,
} from "@gnu-taler/taler-util";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
@@ -50,7 +50,7 @@ export function useAccountInformation(paytoHash?: string) {
}
const { data, error } = useSWR<
- TalerExchangeResultByMethod<"getAmlAttributesForAccount">,
+ TalerExchangeResultByMethod2<"getAmlAttributesForAccount">,
TalerHttpError
>(!session ? undefined : [session, paytoHash], fetcher, {
refreshInterval: 0,
diff --git a/packages/aml-backoffice-ui/src/hooks/decisions.ts
b/packages/aml-backoffice-ui/src/hooks/decisions.ts
index 7a0846ca4..29b8ef222 100644
--- a/packages/aml-backoffice-ui/src/hooks/decisions.ts
+++ b/packages/aml-backoffice-ui/src/hooks/decisions.ts
@@ -17,14 +17,10 @@ import { useState } from "preact/hooks";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
import {
- AmlDecision,
- HttpStatusCode,
OfficerAccount,
- OperationFail,
OperationOk,
opFixedSuccess,
- TalerError,
- TalerExchangeResultByMethod,
+ TalerExchangeResultByMethod2,
TalerHttpError,
} from "@gnu-taler/taler-util";
import { useExchangeApiContext } from "@gnu-taler/web-util/browser";
@@ -70,7 +66,7 @@ export function useCurrentDecisions({
}
const { data, error } = useSWR<
- TalerExchangeResultByMethod<"getAmlDecisions">,
+ TalerExchangeResultByMethod2<"getAmlDecisions">,
TalerHttpError
>(
!session ? undefined : [session, offset, investigated, "getAmlDecisions"],
@@ -121,7 +117,7 @@ export function useAccountDecisions(accountStr: string) {
}
const { data, error } = useSWR<
- TalerExchangeResultByMethod<"getAmlDecisions">,
+ TalerExchangeResultByMethod2<"getAmlDecisions">,
TalerHttpError
>(
!session ? undefined : [session, accountStr, offset, "getAmlDecisions"],
@@ -171,7 +167,7 @@ export function useAccountActiveDecision(accountStr?:
string) {
}
const { data, error } = useSWR<
- TalerExchangeResultByMethod<"getAmlDecisions">,
+ TalerExchangeResultByMethod2<"getAmlDecisions">,
TalerHttpError
>(
!session ? undefined : [session, accountStr, offset, "getAmlDecisions"],
diff --git a/packages/aml-backoffice-ui/src/hooks/server-info.ts
b/packages/aml-backoffice-ui/src/hooks/server-info.ts
index b10f2f7d6..0096fef8a 100644
--- a/packages/aml-backoffice-ui/src/hooks/server-info.ts
+++ b/packages/aml-backoffice-ui/src/hooks/server-info.ts
@@ -16,9 +16,7 @@
import {
AbsoluteTime,
CounterResultByEventName,
- EventReporting_TOPS_calculation,
EventReporting_TOPS_queries,
- EventReporting_VQF_calculation,
EventReporting_VQF_queries,
fetchTopsInfoFromServer,
fetchVqfInfoFromServer,
@@ -26,16 +24,15 @@ import {
OfficerAccount,
OperationOk,
opFixedSuccess,
- TalerExchangeHttpClient,
- TalerExchangeResultByMethod,
+ TalerExchangeResultByMethod2,
TalerHttpError,
TOPS_AmlEventsName,
} from "@gnu-taler/taler-util";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
import { useExchangeApiContext } from "@gnu-taler/web-util/browser";
+import { endOfYear, setYear, startOfYear } from "date-fns";
import _useSWR, { SWRHook } from "swr";
import { useOfficer } from "./officer.js";
-import { endOfYear, setYear, startOfYear } from "date-fns";
const useSWR = _useSWR as unknown as SWRHook;
export function useServerMeasures() {
@@ -51,7 +48,7 @@ export function useServerMeasures() {
}
const { data, error } = useSWR<
- TalerExchangeResultByMethod<"getAmlMeasures">,
+ TalerExchangeResultByMethod2<"getAmlMeasures">,
TalerHttpError
>(!session ? undefined : [session], fetcher, {
refreshInterval: 0,
diff --git a/packages/aml-backoffice-ui/src/hooks/transfers.ts
b/packages/aml-backoffice-ui/src/hooks/transfers.ts
index eef7eb129..7df794927 100644
--- a/packages/aml-backoffice-ui/src/hooks/transfers.ts
+++ b/packages/aml-backoffice-ui/src/hooks/transfers.ts
@@ -20,8 +20,7 @@ import {
AmountJson,
OfficerAccount,
OperationOk,
- opFixedSuccess,
- TalerExchangeResultByMethod,
+ TalerExchangeResultByMethod2,
TalerHttpError,
} from "@gnu-taler/taler-util";
import { useExchangeApiContext } from "@gnu-taler/web-util/browser";
@@ -68,7 +67,7 @@ export function useTransferDebit() {
}
const { data, error } = useSWR<
- TalerExchangeResultByMethod<"getTransfersDebit">,
+ TalerExchangeResultByMethod2<"getTransfersDebit">,
TalerHttpError
>(!session ? undefined : [session, offset, "getTransfersDebit"], fetcher);
@@ -121,7 +120,7 @@ export function useTransferList({
}
const { data, error } = useSWR<
- TalerExchangeResultByMethod<"getTransfersCredit">,
+ TalerExchangeResultByMethod2<"getTransfersCredit">,
TalerHttpError
>(
!session
@@ -139,7 +138,6 @@ export function useTransferList({
);
}
-
type PaginatedResult<T> = OperationOk<T> & {
isLastPage: boolean;
isFirstPage: boolean;
diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
index ed228a50a..990da4fe0 100644
--- a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
+++ b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
@@ -54,16 +54,13 @@ import { Fragment, h, Ref, VNode } from "preact";
import { useState } from "preact/hooks";
import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js";
import { useAccountInformation } from "../hooks/account.js";
-import {
- DecisionRequest,
-} from "../hooks/decision-request.js";
+import { DecisionRequest } from "../hooks/decision-request.js";
import { useAccountDecisions } from "../hooks/decisions.js";
import { useOfficer } from "../hooks/officer.js";
import { useServerMeasures } from "../hooks/server-info.js";
import { CurrentMeasureTable, MeasureInfo, Mesaures } from
"./MeasuresTable.js";
import { Officer } from "./Officer.js";
import { RulesInfo } from "./RulesInfo.js";
-import { ShowConsolidated } from "./ShowConsolidated.js";
// export type AmlEvent =
// | AmlFormEvent
@@ -172,7 +169,6 @@ export function CaseDetails({
// const events = getEventsFromAmlHistory(accountDetails, i18n);
-
function ShortcutActionButtons(): VNode {
return (
<div>
diff --git a/packages/aml-backoffice-ui/src/pages/Search.tsx
b/packages/aml-backoffice-ui/src/pages/Search.tsx
index 43e2419cf..f6b4c9775 100644
--- a/packages/aml-backoffice-ui/src/pages/Search.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Search.tsx
@@ -38,7 +38,6 @@ import {
Loading,
Time,
UIFormElementConfig,
- UIHandlerId,
useExchangeApiContext,
useForm,
useTranslationContext,
@@ -52,7 +51,6 @@ import { privatePages } from "../Routing.js";
import { Pagination, ToInvestigateIcon } from "./Cases.js";
import { HandleAccountNotReady } from "./HandleAccountNotReady.js";
import { Officer } from "./Officer.js";
-import { DecisionRequest } from "../hooks/decision-request.js";
export function Search({
onNewDecision,
@@ -298,10 +296,7 @@ function ShowResult({
// payto: encodeCrockForURI(paytoStr),
// })}
onClick={async () => {
- onNewDecision(
- account,
- encodeCrockForURI(paytoStr),
- );
+ onNewDecision(account, encodeCrockForURI(paytoStr));
}}
class="text-indigo-600 hover:text-indigo-900"
>
diff --git a/packages/aml-backoffice-ui/src/pages/ShowCollectedInfo.tsx
b/packages/aml-backoffice-ui/src/pages/ShowCollectedInfo.tsx
index d0e007b07..a98fe7ce9 100644
--- a/packages/aml-backoffice-ui/src/pages/ShowCollectedInfo.tsx
+++ b/packages/aml-backoffice-ui/src/pages/ShowCollectedInfo.tsx
@@ -13,7 +13,6 @@ import {
FormUI,
Loading,
RouteDefinition,
- useExchangeApiContext,
useForm,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
diff --git a/packages/aml-backoffice-ui/src/pages/Transfers.tsx
b/packages/aml-backoffice-ui/src/pages/Transfers.tsx
index 6a217c736..7215f9312 100644
--- a/packages/aml-backoffice-ui/src/pages/Transfers.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Transfers.tsx
@@ -1,3 +1,14 @@
+import {
+ AbsoluteTime,
+ AmountJson,
+ Amounts,
+ assertUnreachable,
+ CurrencySpecification,
+ encodeCrock,
+ hashNormalizedPaytoUri,
+ HttpStatusCode,
+ TalerError,
+} from "@gnu-taler/taler-util";
import {
Attention,
FormDesign,
@@ -5,27 +16,15 @@ import {
Loading,
RouteDefinition,
Time,
- UIHandlerId,
useExchangeApiContext,
useForm,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
+import { format } from "date-fns";
import { Fragment, h, VNode } from "preact";
-import { useTransferList } from "../hooks/transfers.js";
-import {
- AbsoluteTime,
- AmountJson,
- Amounts,
- assertUnreachable,
- CurrencySpecification,
- encodeCrock,
- hashNormalizedPaytoUri,
- HttpStatusCode,
- TalerError,
-} from "@gnu-taler/taler-util";
import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js";
+import { useTransferList } from "../hooks/transfers.js";
import { Officer } from "./Officer.js";
-import { format } from "date-fns";
export function Transfers({
routeToCaseById,
diff --git a/packages/aml-backoffice-ui/src/pages/decision/Rules.tsx
b/packages/aml-backoffice-ui/src/pages/decision/Rules.tsx
index 09b8ab998..d95bf8a7f 100644
--- a/packages/aml-backoffice-ui/src/pages/decision/Rules.tsx
+++ b/packages/aml-backoffice-ui/src/pages/decision/Rules.tsx
@@ -21,7 +21,6 @@ import {
FormDesign,
FormUI,
InternationalizationAPI,
- Loading,
onComponentUnload,
useExchangeApiContext,
useForm,
@@ -30,7 +29,6 @@ import {
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { useCurrentDecisionRequest } from "../../hooks/decision-request.js";
-import { useAccountActiveDecision } from "../../hooks/decisions.js";
import { useServerMeasures } from "../../hooks/server-info.js";
import { ShowDecisionLimitInfo } from "../CaseDetails.js";
import { RulesInfo } from "../RulesInfo.js";
@@ -119,14 +117,10 @@ export function findRuleInconsistency(
* @param param0
* @returns
*/
-export function Rules({
- newPayto,
-}: {
- newPayto?: PaytoString;
-}): VNode {
+export function Rules({ newPayto }: { newPayto?: PaytoString }): VNode {
const { i18n } = useTranslationContext();
const { config } = useExchangeApiContext();
- const [request] = useCurrentDecisionRequest()
+ const [request] = useCurrentDecisionRequest();
let newPaytoParsed: PaytoUri | undefined;
const isNewAccountAWallet =
@@ -148,14 +142,15 @@ export function Rules({
? undefined
: measures.body.roots;
- const defaultRules =
- (!measures || measures instanceof TalerError || measures.type === "fail"
+ const defaultRules = (
+ !measures || measures instanceof TalerError || measures.type === "fail"
? []
- : measures.body.default_rules).filter((r) => {
- return isWallet
- ? WALLET_RULES.includes(r.operation_type)
- : BANK_RULES.includes(r.operation_type);
- });
+ : measures.body.default_rules
+ ).filter((r) => {
+ return isWallet
+ ? WALLET_RULES.includes(r.operation_type)
+ : BANK_RULES.includes(r.operation_type);
+ });
return (
<div>
@@ -180,7 +175,9 @@ export function Rules({
) : (
<ShowDecisionLimitInfo
fixed
-
since={AbsoluteTime.fromProtocolTimestamp(request.original.decision_time)}
+ since={AbsoluteTime.fromProtocolTimestamp(
+ request.original.decision_time,
+ )}
until={AbsoluteTime.fromProtocolTimestamp(
request.original.limits.expiration_time,
)}
@@ -258,11 +255,10 @@ function UpdateRulesForm({
limits: LegitimizationRuleSet;
isWallet: boolean | undefined;
rootMeasures: AvailableMeasureSummary["roots"] | undefined;
- defaultRules: KycRule[]
+ defaultRules: KycRule[];
}): VNode {
const { i18n } = useTranslationContext();
- const [request, updateRequest] =
- useCurrentDecisionRequest();
+ const [request, updateRequest] = useCurrentDecisionRequest();
const [showAddRuleForm, setShowAddRuleForm] = useState(false);
const measureList = !rootMeasures ? [] : Object.keys(rootMeasures);
const customMeasures = Object.keys(request.custom_measures ?? {});
@@ -270,7 +266,9 @@ function UpdateRulesForm({
...measureList,
...customMeasures,
]);
- const [currentRules, setRules] = useState<KycRule[]>(!request.rules ?
limits.rules : request.rules);
+ const [currentRules, setRules] = useState<KycRule[]>(
+ !request.rules ? limits.rules : request.rules,
+ );
const expirationForm = useForm<ExpirationFormType>(expirationFormDesign, {
expiration:
request.deadline ??
@@ -284,7 +282,7 @@ function UpdateRulesForm({
? undefined
: expirationForm.status.result.expiration;
const doesntExpire = !deadline || AbsoluteTime.isNever(deadline);
- updateRequest("unload rules",{
+ updateRequest("unload rules", {
rules: currentRules,
deadline,
onExpire_measure:
@@ -427,7 +425,7 @@ function UpdateRulesForm({
</button>
<button
onClick={() => {
- setRules( FREEZE_PLAN(config.currency, isWallet));
+ setRules(FREEZE_PLAN(config.currency, isWallet));
}}
class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm
bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
>
@@ -435,7 +433,7 @@ function UpdateRulesForm({
</button>
<button
onClick={() => {
- setRules( BASIC_PLAN(config.currency, isWallet));
+ setRules(BASIC_PLAN(config.currency, isWallet));
}}
class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm
bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
>
@@ -443,7 +441,7 @@ function UpdateRulesForm({
</button>
<button
onClick={() => {
- setRules( PREMIUM_PLAN(config.currency, isWallet));
+ setRules(PREMIUM_PLAN(config.currency, isWallet));
}}
class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm
bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
>
@@ -451,7 +449,7 @@ function UpdateRulesForm({
</button>
<button
onClick={() => {
- setRules( E_COMMERCE(config.currency, isWallet));
+ setRules(E_COMMERCE(config.currency, isWallet));
}}
class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm
bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
>
@@ -459,7 +457,7 @@ function UpdateRulesForm({
</button>
<button
onClick={() => {
- setRules( POINT_OF_SALE(config.currency, isWallet));
+ setRules(POINT_OF_SALE(config.currency, isWallet));
}}
class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm
bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
>
@@ -954,62 +952,62 @@ const POINT_OF_SALE: TemplateRulesFunction = (currency,
isWallet) =>
: BANK_RULES.includes(r.operation_type);
});
- const E_COMMERCE: TemplateRulesFunction = (currency, isWallet) =>
- [
- {
- display_priority: 1,
- measures: ["VERBOTEN"],
- operation_type: LimitOperationType.withdraw,
- threshold: Amounts.stringify({
- currency,
- fraction: 0,
- value: 0,
- }),
- timeframe: Duration.toTalerProtocolDuration(
- Duration.fromSpec({ months: 1 }),
- ),
- },
- {
- display_priority: 1,
- measures: ["VERBOTEN"],
- operation_type: LimitOperationType.merge,
- threshold: Amounts.stringify({
- currency,
- fraction: 0,
- value: 0,
- }),
- timeframe: Duration.toTalerProtocolDuration(
- Duration.fromSpec({ months: 1 }),
- ),
- },
- {
- display_priority: 1,
- measures: ["preserve-investigate"],
- operation_type: LimitOperationType.deposit,
- threshold: Amounts.stringify({
- currency,
- fraction: 0,
- value: 25 * 1000,
- }),
- timeframe: Duration.toTalerProtocolDuration(
- Duration.fromSpec({ months: 1 }),
- ),
- },
- {
- display_priority: 1,
- measures: ["preserve-investigate"],
- operation_type: LimitOperationType.aggregate,
- threshold: Amounts.stringify({
- currency,
- fraction: 0,
- value: 25 * 1000,
- }),
- timeframe: Duration.toTalerProtocolDuration(
- Duration.fromSpec({ months: 1 }),
- ),
- },
- ].filter((r) => {
- return isWallet
- ? WALLET_RULES.includes(r.operation_type)
- : BANK_RULES.includes(r.operation_type);
- });
\ No newline at end of file
+const E_COMMERCE: TemplateRulesFunction = (currency, isWallet) =>
+ [
+ {
+ display_priority: 1,
+ measures: ["VERBOTEN"],
+ operation_type: LimitOperationType.withdraw,
+ threshold: Amounts.stringify({
+ currency,
+ fraction: 0,
+ value: 0,
+ }),
+ timeframe: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({ months: 1 }),
+ ),
+ },
+ {
+ display_priority: 1,
+ measures: ["VERBOTEN"],
+ operation_type: LimitOperationType.merge,
+ threshold: Amounts.stringify({
+ currency,
+ fraction: 0,
+ value: 0,
+ }),
+ timeframe: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({ months: 1 }),
+ ),
+ },
+ {
+ display_priority: 1,
+ measures: ["preserve-investigate"],
+ operation_type: LimitOperationType.deposit,
+ threshold: Amounts.stringify({
+ currency,
+ fraction: 0,
+ value: 25 * 1000,
+ }),
+ timeframe: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({ months: 1 }),
+ ),
+ },
+ {
+ display_priority: 1,
+ measures: ["preserve-investigate"],
+ operation_type: LimitOperationType.aggregate,
+ threshold: Amounts.stringify({
+ currency,
+ fraction: 0,
+ value: 25 * 1000,
+ }),
+ timeframe: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({ months: 1 }),
+ ),
+ },
+ ].filter((r) => {
+ return isWallet
+ ? WALLET_RULES.includes(r.operation_type)
+ : BANK_RULES.includes(r.operation_type);
+ });
diff --git a/packages/bank-ui/src/hooks/account.ts
b/packages/bank-ui/src/hooks/account.ts
index 2f4eda7c7..a555614d6 100644
--- a/packages/bank-ui/src/hooks/account.ts
+++ b/packages/bank-ui/src/hooks/account.ts
@@ -23,18 +23,15 @@ import {
TalerCoreBankResultByMethod,
TalerError,
TalerHttpError,
- WithdrawalOperationStatusFlag,
} from "@gnu-taler/taler-util";
-import { useState, useMemo } from "preact/hooks";
+import { useState } from "preact/hooks";
import { useSessionState } from "./session.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
import {
- delayMs,
- preventBurst,
useAsync,
- useLongPolling,
useBankCoreApiContext,
+ useLongPolling,
} from "@gnu-taler/web-util/browser";
import _useSWR, { mutate, SWRHook } from "swr";
import { PAGINATED_LIST_REQUEST } from "../utils.js";
diff --git a/packages/kyc-ui/src/hooks/kyc.ts b/packages/kyc-ui/src/hooks/kyc.ts
index 4efdfc6ff..6f8e1d13f 100644
--- a/packages/kyc-ui/src/hooks/kyc.ts
+++ b/packages/kyc-ui/src/hooks/kyc.ts
@@ -13,11 +13,11 @@
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 { HttpStatusCode } from "@gnu-taler/taler-util";
-import { opFixedSuccess } from "@gnu-taler/taler-util";
import {
AccessToken,
+ HttpStatusCode,
KycProcessClientInformationWithEtag,
+ opFixedSuccess,
} from "@gnu-taler/taler-util";
import {
useAsync,
@@ -44,7 +44,7 @@ export function useKycInfo(token?: AccessToken) {
token === undefined
? undefined
: () => {
- return api.checkKycInfo(token, undefined);
+ return api.checkKycInfoSpa(token, undefined);
},
[token],
);
@@ -57,7 +57,7 @@ export function useKycInfo(token?: AccessToken) {
return result.body;
},
async (latestStatus: KycProcessClientInformationWithEtag) => {
- const res = await api.checkKycInfo(token!, latestStatus.etag, {
+ const res = await api.checkKycInfoSpa(token!, latestStatus.etag, {
timeoutMs: 5000,
});
if (res.type === "fail" && res.case === HttpStatusCode.NotModified) {
diff --git a/packages/kyc-ui/src/pages/FillForm.tsx
b/packages/kyc-ui/src/pages/FillForm.tsx
index a0b863265..bf6b0e93e 100644
--- a/packages/kyc-ui/src/pages/FillForm.tsx
+++ b/packages/kyc-ui/src/pages/FillForm.tsx
@@ -16,10 +16,10 @@
import {
AbsoluteTime,
AccessToken,
- AmountJson,
- Amounts,
HttpStatusCode,
KycRequirementInformation,
+ KycRequirementInformationId,
+ TalerFormAttributes,
assertUnreachable,
} from "@gnu-taler/taler-util";
import {
@@ -42,8 +42,6 @@ import { Fragment, VNode, h } from "preact";
import { usePreferences } from "../context/preferences.js";
import { useUiFormsContext } from "../context/ui-forms.js";
import { preloadedForms } from "../forms/index.js";
-import { TalerFormAttributes } from "@gnu-taler/taler-util";
-import { KycRequirementInformationId } from "@gnu-taler/taler-util";
const TALER_SCREEN_ID = 103;
@@ -57,7 +55,7 @@ type Props = {
type FormType = {
form_id: string;
[TalerFormAttributes.FORM_ID]: string;
- [TalerFormAttributes.FORM_VERSION]: number,
+ [TalerFormAttributes.FORM_VERSION]: number;
// state: TalerExchangeApi.AmlState;
};
@@ -149,7 +147,7 @@ function ShowForm({
case HttpStatusCode.Conflict:
return i18n.str`Officer disabled or more recent decision was
already submitted.`;
default:
- assertUnreachable(fail.case);
+ assertUnreachable(fail);
}
},
);
@@ -234,20 +232,12 @@ export function FillForm({
if (!reqId) {
return (
<Attention title={i18n.str`Can't upload information`} type="danger">
- <i18n.Translate>
- The KYC requirement doesn't have an ID
- </i18n.Translate>
+ <i18n.Translate>The KYC requirement doesn't have an ID</i18n.Translate>
</Attention>
);
}
- return (
- <ShowForm
- onComplete={onComplete}
- reqId={reqId}
- theForm={theForm}
- />
- );
+ return <ShowForm onComplete={onComplete} reqId={reqId} theForm={theForm} />;
}
function searchForm(
diff --git a/packages/taler-harness/src/harness/environments.ts
b/packages/taler-harness/src/harness/environments.ts
index ac56d857e..b4c598d63 100644
--- a/packages/taler-harness/src/harness/environments.ts
+++ b/packages/taler-harness/src/harness/environments.ts
@@ -46,7 +46,7 @@ import {
succeedOrThrow,
TalerCorebankApiClient,
TalerCoreBankHttpClient,
- TalerExchangeHttpClient2,
+ TalerExchangeHttpClient,
TalerMerchantApi,
TalerMerchantInstanceHttpClient,
TalerProtocolTimestamp,
@@ -1098,7 +1098,7 @@ export interface KycTestEnv {
amlKeypair: EddsaKeyPairStrings;
merchant: MerchantService;
bankApi: TalerCoreBankHttpClient;
- exchangeApi: TalerExchangeHttpClient2;
+ exchangeApi: TalerExchangeHttpClient;
wireGatewayApi: TalerWireGatewayHttpClient;
merchantApi: TalerMerchantInstanceHttpClient;
}
@@ -1272,7 +1272,7 @@ export async function createKycTestkudosEnvironment(
harnessHttpLib,
);
- const exchangeApi = new TalerExchangeHttpClient2(exchange.baseUrl, {
+ const exchangeApi = new TalerExchangeHttpClient(exchange.baseUrl, {
httpClient: harnessHttpLib,
});
diff --git a/packages/taler-harness/src/harness/tops.ts
b/packages/taler-harness/src/harness/tops.ts
index 90d50b8f5..bff73afc3 100644
--- a/packages/taler-harness/src/harness/tops.ts
+++ b/packages/taler-harness/src/harness/tops.ts
@@ -36,7 +36,6 @@ import {
TalerCorebankApiClient,
TalerCoreBankHttpClient,
TalerExchangeHttpClient,
- TalerExchangeHttpClient2,
TalerMerchantInstanceHttpClient,
TalerProtocolDuration,
TalerProtocolTimestamp,
@@ -948,7 +947,7 @@ export interface MeasuresTestEnvironment {
challengerPostal: TestfakeChallengerService;
challengerSms: TestfakeChallengerService;
officerAcc: OfficerAccount;
- exchangeClient: TalerExchangeHttpClient2;
+ exchangeClient: TalerExchangeHttpClient;
}
export async function setupMeasuresTestEnvironment(
@@ -975,7 +974,7 @@ export async function setupMeasuresTestEnvironment(
const merchantClient = new TalerMerchantInstanceHttpClient(
merchant.makeInstanceBaseUrl(),
);
- const exchangeClient = new TalerExchangeHttpClient2(exchange.baseUrl, {
+ const exchangeClient = new TalerExchangeHttpClient(exchange.baseUrl, {
httpClient: harnessHttpLib,
});
@@ -1143,7 +1142,7 @@ async function doTriggerReset(
t: GlobalTestState,
args: {
officerAcc: OfficerAccount;
- exchangeClient: TalerExchangeHttpClient2;
+ exchangeClient: TalerExchangeHttpClient;
merchantPaytoHash: string;
},
): Promise<void> {
@@ -1205,7 +1204,7 @@ async function doTriggerMeasure(
t: GlobalTestState,
args: {
officerAcc: OfficerAccount;
- exchangeClient: TalerExchangeHttpClient2;
+ exchangeClient: TalerExchangeHttpClient;
merchantPaytoHash: string;
measure: string;
},
diff --git
a/packages/taler-harness/src/integrationtests/test-withdrawal-idempotent.ts
b/packages/taler-harness/src/integrationtests/test-withdrawal-idempotent.ts
index 147480442..f41fe0469 100644
--- a/packages/taler-harness/src/integrationtests/test-withdrawal-idempotent.ts
+++ b/packages/taler-harness/src/integrationtests/test-withdrawal-idempotent.ts
@@ -25,7 +25,7 @@ import {
ExchangeWithdrawRequest,
getRandomBytes,
succeedOrThrow,
- TalerExchangeHttpClient2,
+ TalerExchangeHttpClient,
} from "@gnu-taler/taler-util";
import { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
import {
@@ -117,7 +117,7 @@ async function myWithdrawCoin(args: {
value: Amounts.parseOrThrow(denom.value),
});
- const exchangeClient = new TalerExchangeHttpClient2(exchangeBaseUrl);
+ const exchangeClient = new TalerExchangeHttpClient(exchangeBaseUrl);
const sigResp = await cryptoApi.signWithdrawal({
amount: Amounts.stringify(denom.value),
diff --git a/packages/taler-util/src/aml/reporting.ts
b/packages/taler-util/src/aml/reporting.ts
index cd1a76772..610dea005 100644
--- a/packages/taler-util/src/aml/reporting.ts
+++ b/packages/taler-util/src/aml/reporting.ts
@@ -1,4 +1,10 @@
-import { AbsoluteTime, Duration, OfficerAccount, TalerExchangeHttpClient,
TOPS_AmlEventsName } from "../index.js";
+import {
+ AbsoluteTime,
+ Duration,
+ OfficerAccount,
+ TalerExchangeHttpClient,
+ TOPS_AmlEventsName,
+} from "../index.js";
/**
* Define a set of parameters to make a request to the server
@@ -21,7 +27,7 @@ export type QueryModel<Ev> = {
* https://docs.taler.net/deployments/tops.html#event-reporting-tops
*
* Maps a request key to request parameters
- *
+ *
*/
export const EventReporting_TOPS_queries = {
// Number of accounts that are opened
@@ -107,12 +113,12 @@ export const EventReporting_TOPS_queries = {
/**
* All the calculation needed to create the Event Reporting (TOPS)
* https://docs.taler.net/deployments/tops.html#event-reporting-tops
- *
- * Maps a event reporting name with a calculation which uses the
+ *
+ * Maps a event reporting name with a calculation which uses the
* result of a query to the server.
- *
+ *
* @param events The result of event reporting query
- * @returns
+ * @returns
*/
export const EventReporting_TOPS_calculation = (
events: CounterResultByEventName<typeof EventReporting_TOPS_queries>,
@@ -159,9 +165,12 @@ export const EventReporting_TOPS_calculation = (
*
* Maps a request key to request parameters.
* Requires the times for the query range.
- *
+ *
*/
-export const EventReporting_VQF_queries = (jan_1st: AbsoluteTime, dec_31st:
AbsoluteTime) => {
+export const EventReporting_VQF_queries = (
+ jan_1st: AbsoluteTime,
+ dec_31st: AbsoluteTime,
+) => {
const zero = AbsoluteTime.fromMilliseconds(0);
return {
@@ -256,7 +265,9 @@ export const EventReporting_VQF_queries = (jan_1st:
AbsoluteTime, dec_31st: Abso
};
export const EventReporting_VQF_calculation = (
- events: CounterResultByEventName<ReturnType<typeof
EventReporting_VQF_queries>>,
+ events: CounterResultByEventName<
+ ReturnType<typeof EventReporting_VQF_queries>
+ >,
) => {
return {
// Number of open accounts on January 1st (self-declaration 3.1.1)
@@ -336,8 +347,10 @@ function safeAdd(
return a === undefined || b == undefined ? undefined : a + b;
}
-
-export async function fetchTopsInfoFromServer(api: TalerExchangeHttpClient,
officer: OfficerAccount) {
+export async function fetchTopsInfoFromServer(
+ api: TalerExchangeHttpClient,
+ officer: OfficerAccount,
+) {
type EventType = typeof EventReporting_TOPS_queries;
const eventList = Object.entries(EventReporting_TOPS_queries);
@@ -361,7 +374,12 @@ export async function fetchTopsInfoFromServer(api:
TalerExchangeHttpClient, offi
return EventReporting_TOPS_calculation(resultMap);
}
-export async function fetchVqfInfoFromServer(api: TalerExchangeHttpClient,
officer: OfficerAccount, jan_1st: AbsoluteTime, dec_31st: AbsoluteTime) {
+export async function fetchVqfInfoFromServer(
+ api: TalerExchangeHttpClient,
+ officer: OfficerAccount,
+ jan_1st: AbsoluteTime,
+ dec_31st: AbsoluteTime,
+) {
const VQF_EVENTS_THIS_YEAR = EventReporting_VQF_queries(jan_1st, dec_31st);
type EventType = typeof VQF_EVENTS_THIS_YEAR;
const eventList = Object.entries(VQF_EVENTS_THIS_YEAR);
diff --git a/packages/taler-util/src/http-client/exchange-client.ts
b/packages/taler-util/src/http-client/exchange-client.ts
index 4ad168193..84c50d31f 100644
--- a/packages/taler-util/src/http-client/exchange-client.ts
+++ b/packages/taler-util/src/http-client/exchange-client.ts
@@ -33,6 +33,7 @@ import {
opEmptySuccess,
opFixedSuccess,
opKnownAlternativeHttpFailure,
+ opKnownFailure,
opKnownHttpFailure,
opSuccessFromHttp,
opUnknownHttpFailure,
@@ -40,12 +41,11 @@ import {
import { encodeCrock } from "../taler-crypto.js";
import {
AccessToken,
- AmountString,
EddsaPublicKeyString,
EddsaSignatureString,
+ LongPollParams,
OfficerAccount,
PaginationParams,
- ReserveAccount,
codecForTalerCommonConfigResponse,
} from "../types-taler-common.js";
import {
@@ -72,12 +72,13 @@ import {
ExchangeWithdrawResponse,
KycAttributes,
KycProcessClientInformation,
+ KycProcessClientInformationWithEtag,
KycProcessStartInformation,
KycRequirementInformationId,
+ LegitimizationMeasuresList,
LegitimizationNeededResponse,
PurseConflict,
PurseConflictPartial,
- WalletKycCheckResponse,
WalletKycRequest,
codecForAccountKycStatus,
codecForAmlDecisionsResponse,
@@ -100,7 +101,12 @@ import {
codecForPurseConflict,
codecForPurseConflictPartial,
} from "../types-taler-exchange.js";
-import { CacheEvictor, addPaginationParams, nullEvictor } from "./utils.js";
+import {
+ CacheEvictor,
+ addLongPollingParam,
+ addPaginationParams,
+ nullEvictor,
+} from "./utils.js";
import { TalerError } from "../errors.js";
import {
@@ -110,20 +116,19 @@ import {
LongpollQueue,
signAmlDecision,
signAmlQuery,
- signWalletAccountSetup,
} from "../index.js";
import { TalerErrorCode } from "../taler-error-codes.js";
import { AbsoluteTime } from "../time.js";
import { EmptyObject, codecForEmptyObject } from "../types-taler-wallet.js";
export type TalerExchangeResultByMethod2<
- prop extends keyof TalerExchangeHttpClient2,
-> = ResultByMethod<TalerExchangeHttpClient2, prop>;
+ prop extends keyof TalerExchangeHttpClient,
+> = ResultByMethod<TalerExchangeHttpClient, prop>;
export type TalerExchangeErrorsByMethod2<
- prop extends keyof TalerExchangeHttpClient2,
-> = FailCasesByMethod<TalerExchangeHttpClient2, prop>;
+ prop extends keyof TalerExchangeHttpClient,
+> = FailCasesByMethod<TalerExchangeHttpClient, prop>;
-export enum TalerExchangeCacheEviction2 {
+export enum TalerExchangeCacheEviction {
UPLOAD_KYC_FORM,
MAKE_AML_DECISION,
}
@@ -131,10 +136,10 @@ export enum TalerExchangeCacheEviction2 {
/**
* Client library for the GNU Taler exchange service.
*/
-export class TalerExchangeHttpClient2 {
+export class TalerExchangeHttpClient {
public static readonly SUPPORTED_EXCHANGE_PROTOCOL_VERSION = "27:0:2";
private httpLib: HttpRequestLibrary;
- private cacheEvictor: CacheEvictor<TalerExchangeCacheEviction2>;
+ private cacheEvictor: CacheEvictor<TalerExchangeCacheEviction>;
private preventCompression: boolean;
private cancelationToken: CancellationToken;
private longPollQueue: LongpollQueue;
@@ -143,7 +148,7 @@ export class TalerExchangeHttpClient2 {
readonly baseUrl: string,
params: {
httpClient?: HttpRequestLibrary;
- cacheEvictor?: CacheEvictor<TalerExchangeCacheEviction2>;
+ cacheEvictor?: CacheEvictor<TalerExchangeCacheEviction>;
preventCompression?: boolean;
cancelationToken?: CancellationToken;
longPollQueue?: LongpollQueue;
@@ -159,7 +164,7 @@ export class TalerExchangeHttpClient2 {
isCompatible(version: string): boolean {
const compare = LibtoolVersion.compare(
- TalerExchangeHttpClient2.SUPPORTED_EXCHANGE_PROTOCOL_VERSION,
+ TalerExchangeHttpClient.SUPPORTED_EXCHANGE_PROTOCOL_VERSION,
version,
);
return compare?.compatible ?? false;
@@ -243,7 +248,7 @@ export class TalerExchangeHttpClient2 {
code: TalerErrorCode.GENERIC_CLIENT_UNSUPPORTED_PROTOCOL_VERSION,
requestUrl: resp.requestUrl,
httpStatusCode: resp.status,
- detail: `Unsupported protocol version, client supports
${TalerExchangeHttpClient2.SUPPORTED_EXCHANGE_PROTOCOL_VERSION}, server
supports ${minBody.version}`,
+ detail: `Unsupported protocol version, client supports
${TalerExchangeHttpClient.SUPPORTED_EXCHANGE_PROTOCOL_VERSION}, server supports
${minBody.version}`,
});
}
// Now that we've checked the basic body, re-parse the full response.
@@ -568,26 +573,10 @@ export class TalerExchangeHttpClient2 {
* https://docs.taler.net/core/api-exchange.html#post--kyc-wallet
*
*/
- async notifyKycBalanceLimit(
- account: ReserveAccount,
- balance: AmountString,
- ): Promise<
- | OperationOk<void>
- | OperationFail<HttpStatusCode.Forbidden>
- | OperationAlternative<
- HttpStatusCode.UnavailableForLegalReasons,
- LegitimizationNeededResponse
- >
- | OperationOk<WalletKycCheckResponse>
- > {
- const body: WalletKycRequest = {
- balance,
- reserve_pub: account.id as any,
- reserve_sig: encodeCrock(
- signWalletAccountSetup(account.signingKey, balance),
- ) as any,
- };
- const resp = await this.fetch(`kyc-wallet`, {
+ async notifyKycBalanceLimit(body: WalletKycRequest) {
+ const url = new URL(`kyc-wallet`, this.baseUrl);
+
+ const resp = await this.httpLib.fetch(url.href, {
method: "POST",
body,
});
@@ -610,6 +599,35 @@ export class TalerExchangeHttpClient2 {
}
}
+ async getAmlLegitimizations(args: {
+ officerAcc: OfficerAccount;
+ }): Promise<OperationOk<LegitimizationMeasuresList>> {
+ const url = new URL(
+ `aml/${args.officerAcc.id}/legitimizations`,
+ this.baseUrl,
+ );
+
+ const resp = await this.httpLib.fetch(url.href, {
+ headers: {
+ "Taler-AML-Officer-Signature": encodeCrock(
+ signAmlQuery(args.officerAcc.signingKey),
+ ),
+ },
+ });
+
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ // FIXME: Parse properly.
+ return opSuccessFromHttp(resp, codecForAny());
+ case HttpStatusCode.NoContent:
+ return opFixedSuccess({
+ measures: [],
+ });
+ default:
+ return opUnknownHttpFailure(resp);
+ }
+ }
+
/**
*
https://docs.taler.net/core/api-exchange.html#get--kyc-check-$H_NORMALIZED_PAYTO
*
@@ -759,6 +777,51 @@ export class TalerExchangeHttpClient2 {
}
}
+ /**
+ * SPA-Specific version of checkKycInfo
+ */
+ async checkKycInfoSpa(
+ token: AccessToken,
+ etag: string | undefined,
+ params: LongPollParams = {},
+ ) {
+ const url = new URL(`kyc-info/${token}`, this.baseUrl);
+
+ addLongPollingParam(url, params);
+
+ const resp = await this.httpLib.fetch(url.href, {
+ method: "GET",
+ headers: {
+ "If-None-Match": etag,
+ },
+ });
+ switch (resp.status) {
+ case HttpStatusCode.Ok: {
+ // we need to add the etag to the response because the
+ // client needs it to repeat the request and
+ // do the long polling
+ const etag = resp.headers.get("etag") ?? undefined;
+ const body = await readSuccessResponseJsonOrThrow(
+ resp,
+ codecForKycProcessClientInformation(),
+ );
+ return opFixedSuccess<KycProcessClientInformationWithEtag>({
+ ...body,
+ etag,
+ });
+ }
+ case HttpStatusCode.Accepted:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NoContent:
+ return opKnownHttpFailure(resp.status, resp);
+ case HttpStatusCode.NotModified:
+ // do not read details from response
+ return opKnownFailure(resp.status);
+ default:
+ return opUnknownHttpFailure(resp);
+ }
+ }
+
/**
* https://docs.taler.net/core/api-exchange.html#post--kyc-upload-$ID
*
@@ -780,7 +843,7 @@ export class TalerExchangeHttpClient2 {
switch (resp.status) {
case HttpStatusCode.NoContent: {
this.cacheEvictor.notifySuccess(
- TalerExchangeCacheEviction2.UPLOAD_KYC_FORM,
+ TalerExchangeCacheEviction.UPLOAD_KYC_FORM,
);
return opEmptySuccess();
}
@@ -1071,7 +1134,7 @@ export class TalerExchangeHttpClient2 {
switch (resp.status) {
case HttpStatusCode.NoContent: {
this.cacheEvictor.notifySuccess(
- TalerExchangeCacheEviction2.MAKE_AML_DECISION,
+ TalerExchangeCacheEviction.MAKE_AML_DECISION,
);
return opEmptySuccess();
}
diff --git a/packages/taler-util/src/http-client/exchange.ts
b/packages/taler-util/src/http-client/exchange.ts
deleted file mode 100644
index 3aa49afe0..000000000
--- a/packages/taler-util/src/http-client/exchange.ts
+++ /dev/null
@@ -1,1001 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2025 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 { codecForAny } from "../codec.js";
-import {
- HttpRequestLibrary,
- readSuccessResponseJsonOrThrow,
-} from "../http-common.js";
-import { HttpStatusCode } from "../http-status-codes.js";
-import { createPlatformHttpLib } from "../http.js";
-import { LibtoolVersion } from "../libtool-version.js";
-import {
- FailCasesByMethod,
- OperationAlternative,
- OperationFail,
- OperationOk,
- ResultByMethod,
- opEmptySuccess,
- opFixedSuccess,
- opKnownAlternativeHttpFailure,
- opKnownFailure,
- opKnownHttpFailure,
- opSuccessFromHttp,
- opUnknownHttpFailure,
-} from "../operation.js";
-import { encodeCrock } from "../taler-crypto.js";
-import {
- AccessToken,
- EddsaPublicKeyString,
- EddsaSignatureString,
- LongPollParams,
- OfficerAccount,
- PaginationParams,
- codecForTalerCommonConfigResponse,
-} from "../types-taler-common.js";
-import {
- AccountKycStatus,
- AmlDecisionRequest,
- ExchangeKycUploadFormRequest,
- ExchangePurseDeposits,
- ExchangePurseMergeRequest,
- ExchangeReservePurseRequest,
- ExchangeVersionResponse,
- KycProcessClientInformation,
- KycRequirementInformationId,
- LegitimizationMeasuresList,
- PurseCreate,
- WalletKycRequest,
- codecForAccountKycStatus,
- codecForAmlDecisionsResponse,
- codecForAmlKycAttributes,
- codecForAmlWalletKycCheckResponse,
- codecForAvailableMeasureSummary,
- codecForEventCounter,
- codecForExchangeConfig,
- codecForExchangeGetContractResponse,
- codecForExchangeKeysResponse,
- codecForExchangeMergeConflictResponse,
- codecForExchangeMergeSuccessResponse,
- codecForExchangePurseStatus,
- codecForExchangeTransferList,
- codecForKycProcessClientInformation,
- codecForKycProcessStartInformation,
- codecForLegitimizationNeededResponse,
- codecForPurseConflict,
- codecForPurseConflictPartial,
-} from "../types-taler-exchange.js";
-import {
- CacheEvictor,
- addLongPollingParam,
- addPaginationParams,
- nullEvictor,
-} from "./utils.js";
-
-import { TalerError } from "../errors.js";
-import {
- AmountJson,
- Amounts,
- CancellationToken,
- LongpollQueue,
- signAmlDecision,
- signAmlQuery,
-} from "../index.js";
-import { TalerErrorCode } from "../taler-error-codes.js";
-import { AbsoluteTime } from "../time.js";
-
-export type TalerExchangeResultByMethod<
- prop extends keyof TalerExchangeHttpClient,
-> = ResultByMethod<TalerExchangeHttpClient, prop>;
-export type TalerExchangeErrorsByMethod<
- prop extends keyof TalerExchangeHttpClient,
-> = FailCasesByMethod<TalerExchangeHttpClient, prop>;
-
-export enum TalerExchangeCacheEviction {
- UPLOAD_KYC_FORM,
- MAKE_AML_DECISION,
-}
-
-declare const __pubId: unique symbol;
-export type ReservePub = string & { [__pubId]: true };
-
-export type KycProcessClientInformationWithEtag =
- KycProcessClientInformation & { etag: string | undefined };
-
-/**
- * Client library for the GNU Taler exchange service.
- *
- * FIXME: This client library is currently used by the SPA.
- * However, we should merge it with the other exchange client implementation.
- */
-export class TalerExchangeHttpClient {
- public static readonly PROTOCOL_VERSION = "28:0:2";
- private httpLib: HttpRequestLibrary;
- private cacheEvictor: CacheEvictor<TalerExchangeCacheEviction>;
- private preventCompression: boolean;
-
- constructor(
- readonly baseUrl: string,
- params: {
- httpClient?: HttpRequestLibrary;
- cacheEvictor?: CacheEvictor<TalerExchangeCacheEviction>;
- preventCompression?: boolean;
- cancelationToken?: CancellationToken;
- longPollQueue?: LongpollQueue;
- },
- ) {
- this.httpLib = params.httpClient ?? createPlatformHttpLib();
- this.cacheEvictor = params.cacheEvictor ?? nullEvictor;
- this.preventCompression = !!params.preventCompression;
- }
-
- isCompatible(version: string): boolean {
- const compare = LibtoolVersion.compare(
- TalerExchangeHttpClient.PROTOCOL_VERSION,
- version,
- );
- return compare?.compatible ?? false;
- }
-
- // EXCHANGE INFORMATION
-
- /**
- * https://docs.taler.net/core/api-exchange.html#get--seed
- *
- */
- async getSeed() {
- const url = new URL(`seed`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- const buffer = await resp.bytes();
- const uintar = new Uint8Array(buffer);
- return opFixedSuccess(uintar);
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
- /**
- * https://docs.taler.net/core/api-exchange.html#get--config
- *
- */
- async getConfig(): Promise<
- | OperationFail<HttpStatusCode.NotFound>
- | OperationOk<ExchangeVersionResponse>
- > {
- const url = new URL(`config`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- });
- switch (resp.status) {
- case HttpStatusCode.Ok: {
- const minBody = await readSuccessResponseJsonOrThrow(
- resp,
- codecForTalerCommonConfigResponse(),
- );
- const expectedName = "taler-exchange";
- if (minBody.name !== expectedName) {
- throw TalerError.fromUncheckedDetail({
- code: TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR,
- requestUrl: resp.requestUrl,
- httpStatusCode: resp.status,
- detail: `Unexpected server component name (got ${minBody.name},
expected ${expectedName}})`,
- });
- }
- if (!this.isCompatible(minBody.version)) {
- throw TalerError.fromUncheckedDetail({
- code: TalerErrorCode.GENERIC_CLIENT_UNSUPPORTED_PROTOCOL_VERSION,
- requestUrl: resp.requestUrl,
- httpStatusCode: resp.status,
- detail: `Unsupported protocol version, client supports
${TalerExchangeHttpClient.PROTOCOL_VERSION}, server supports
${minBody.version}`,
- });
- }
- // Now that we've checked the basic body, re-parse the full response.
- const body = await readSuccessResponseJsonOrThrow(
- resp,
- codecForExchangeConfig(),
- );
- return opFixedSuccess(body);
- }
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- * https://docs.taler.net/core/api-merchant.html#get--config
- *
- * PARTIALLY IMPLEMENTED!!
- */
- async getKeys() {
- const url = new URL(`keys`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForExchangeKeysResponse());
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- // WALLET TO WALLET
-
- /**
- * https://docs.taler.net/core/api-exchange.html#get--purses-$PURSE_PUB-merge
- *
- */
- async getPurseStatusAtMerge(pursePub: EddsaPublicKeyString) {
- const url = new URL(`purses/${pursePub}/merge`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForExchangePurseStatus());
- case HttpStatusCode.Gone:
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- *
https://docs.taler.net/core/api-exchange.html#get--purses-$PURSE_PUB-deposit
- *
- */
- async getPurseStatusAtDeposit(pursePub: EddsaPublicKeyString) {
- const url = new URL(`purses/${pursePub}/deposit`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForExchangePurseStatus());
- case HttpStatusCode.Gone:
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- *
https://docs.taler.net/core/api-exchange.html#post--purses-$PURSE_PUB-create
- *
- */
- async createPurseFromDeposit(
- pursePub: EddsaPublicKeyString,
- body: PurseCreate,
- ) {
- const url = new URL(`purses/${pursePub}/create`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- body,
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- // FIXME: parse PurseCreateSuccessResponse
- return opSuccessFromHttp(resp, codecForAny());
- case HttpStatusCode.Conflict:
- return opKnownAlternativeHttpFailure(
- resp,
- resp.status,
- codecForPurseConflict(),
- );
- case HttpStatusCode.Forbidden:
- case HttpStatusCode.NotFound:
- case HttpStatusCode.TooEarly:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- * https://docs.taler.net/core/api-exchange.html#delete--purses-$PURSE_PUB
- *
- */
- async deletePurse(pursePub: string, purseSig: string) {
- const url = new URL(`purses/${pursePub}`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "DELETE",
- headers: {
- "taler-purse-signature": purseSig,
- },
- });
- switch (resp.status) {
- case HttpStatusCode.NoContent:
- return opEmptySuccess();
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.Conflict:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.Forbidden:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- * POST /purses/$PURSE_PUB/merge
- *
- *
https://docs.taler.net/core/api-exchange.html#post--purses-$PURSE_PUB-merge
- */
- async postPurseMerge(pursePub: string, body: ExchangePurseMergeRequest) {
- const url = new URL(`purses/${pursePub}/merge`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- body,
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForExchangeMergeSuccessResponse());
- case HttpStatusCode.UnavailableForLegalReasons:
- return opKnownAlternativeHttpFailure(
- resp,
- resp.status,
- codecForLegitimizationNeededResponse(),
- );
- case HttpStatusCode.Conflict:
- return opKnownAlternativeHttpFailure(
- resp,
- resp.status,
- codecForExchangeMergeConflictResponse(),
- );
- case HttpStatusCode.Gone:
- case HttpStatusCode.Forbidden:
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- *
https://docs.taler.net/core/api-exchange.html#post--reserves-$RESERVE_PUB-purse
- *
- */
- async createPurseFromReserve(
- pursePub: EddsaPublicKeyString,
- body: ExchangeReservePurseRequest,
- ) {
- const url = new URL(`reserves/${pursePub}/purse`, this.baseUrl);
-
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- body,
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- // FIXME: parse PurseCreateSuccessResponse
- return opSuccessFromHttp(resp, codecForAny());
- case HttpStatusCode.PaymentRequired:
- case HttpStatusCode.Forbidden:
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.Conflict:
- return opKnownAlternativeHttpFailure(
- resp,
- resp.status,
- codecForPurseConflictPartial(),
- );
- case HttpStatusCode.UnavailableForLegalReasons:
- return opKnownAlternativeHttpFailure(
- resp,
- resp.status,
- codecForLegitimizationNeededResponse(),
- );
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- * https://docs.taler.net/core/api-exchange.html#get--contracts-$CONTRACT_PUB
- *
- */
- async getContract(pursePub: EddsaPublicKeyString) {
- const url = new URL(`contracts/${pursePub}`, this.baseUrl);
-
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForExchangeGetContractResponse());
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- *
https://docs.taler.net/core/api-exchange.html#post--purses-$PURSE_PUB-deposit
- *
- */
- async depositIntoPurse(
- pursePub: EddsaPublicKeyString,
- body: ExchangePurseDeposits,
- ) {
- const url = new URL(`purses/${pursePub}/deposit`, this.baseUrl);
-
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- body,
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- // FIXME: parse PurseDepositSuccessResponse
- return opSuccessFromHttp(resp, codecForAny());
- case HttpStatusCode.Conflict:
- return opKnownAlternativeHttpFailure(
- resp,
- resp.status,
- codecForPurseConflict(),
- );
- case HttpStatusCode.Forbidden:
- case HttpStatusCode.NotFound:
- case HttpStatusCode.Gone:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- // WADS
-
- /**
- * https://docs.taler.net/core/api-exchange.html#get--wads-$WAD_ID
- *
- */
- async getWadInfo(): Promise<never> {
- throw Error("not yet implemented");
- }
-
- //
- // KYC
- //
-
- /**
- * https://docs.taler.net/core/api-exchange.html#post--kyc-wallet
- *
- */
- async notifyKycBalanceLimit(body: WalletKycRequest) {
- const url = new URL(`kyc-wallet`, this.baseUrl);
-
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- body,
- });
-
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForAmlWalletKycCheckResponse());
- case HttpStatusCode.NoContent:
- return opEmptySuccess();
- case HttpStatusCode.Forbidden:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.UnavailableForLegalReasons:
- return opKnownAlternativeHttpFailure(
- resp,
- resp.status,
- codecForLegitimizationNeededResponse(),
- );
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- * Endpoint: GET /kyc-check/$H_NORMALIZED_PAYTO
- *
- *
https://docs.taler.net/core/api-exchange.html#get--kyc-check-$H_NORMALIZED_PAYTO
- */
- async checkKycStatus(args: {
- paytoHash: string;
- accountPub: EddsaPublicKeyString;
- accountSig: EddsaSignatureString;
- longpoll?: boolean;
- awaitAuth?: boolean;
- }): Promise<
- | OperationOk<void>
- | OperationAlternative<HttpStatusCode.Ok, AccountKycStatus>
- | OperationAlternative<HttpStatusCode.Accepted, AccountKycStatus>
- | OperationFail<HttpStatusCode.Forbidden>
- | OperationFail<HttpStatusCode.NotFound>
- | OperationFail<HttpStatusCode.Conflict>
- > {
- const { paytoHash, accountPub, accountSig, longpoll, awaitAuth } = args;
- const url = new URL(`kyc-check/${paytoHash}`, this.baseUrl);
- if (awaitAuth !== undefined) {
- url.searchParams.set("await_auth", awaitAuth ? "YES" : "NO");
- }
-
- const resp = await this.httpLib.fetch(url.href, {
- headers: {
- "Account-Owner-Signature": accountSig,
- "Account-Owner-Pub": accountPub,
- },
- });
-
- switch (resp.status) {
- case HttpStatusCode.Ok:
- case HttpStatusCode.Accepted:
- return opKnownAlternativeHttpFailure(
- resp,
- resp.status,
- codecForAccountKycStatus(),
- );
- case HttpStatusCode.NoContent:
- return opEmptySuccess();
- case HttpStatusCode.Forbidden:
- case HttpStatusCode.NotFound:
- case HttpStatusCode.Conflict:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- * https://docs.taler.net/core/api-exchange.html#get--kyc-info-$ACCESS_TOKEN
- *
- */
- async checkKycInfo(
- token: AccessToken,
- etag: string | undefined,
- params: LongPollParams = {},
- ) {
- const url = new URL(`kyc-info/${token}`, this.baseUrl);
-
- addLongPollingParam(url, params);
-
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- headers: {
- "If-None-Match": etag,
- },
- });
- switch (resp.status) {
- case HttpStatusCode.Ok: {
- // we need to add the etag to the response because the
- // client needs it to repeat the request and
- // do the long polling
- const etag = resp.headers.get("etag") ?? undefined;
- const body = await readSuccessResponseJsonOrThrow(
- resp,
- codecForKycProcessClientInformation(),
- );
- return opFixedSuccess<KycProcessClientInformationWithEtag>({
- ...body,
- etag,
- });
- }
- case HttpStatusCode.Accepted:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.NoContent:
- return opKnownHttpFailure(resp.status, resp);
- case HttpStatusCode.NotModified:
- // do not read details from response
- return opKnownFailure(resp.status);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- * https://docs.taler.net/core/api-exchange.html#post--kyc-upload-$ID
- *
- */
- async uploadKycForm<T extends ExchangeKycUploadFormRequest>(
- requirement: KycRequirementInformationId,
- body: T,
- ) {
- const url = new URL(`kyc-upload/${requirement}`, this.baseUrl);
-
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- body,
- compress: this.preventCompression ? undefined : "deflate",
- });
- switch (resp.status) {
- case HttpStatusCode.NoContent: {
- this.cacheEvictor.notifySuccess(
- TalerExchangeCacheEviction.UPLOAD_KYC_FORM,
- );
- return opEmptySuccess();
- }
- case HttpStatusCode.NotFound:
- case HttpStatusCode.Conflict:
- case HttpStatusCode.PayloadTooLarge:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- * https://docs.taler.net/core/api-exchange.html#post--kyc-start-$ID
- *
- */
- 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,
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForKycProcessStartInformation());
- case HttpStatusCode.NotFound:
- case HttpStatusCode.Conflict:
- case HttpStatusCode.PayloadTooLarge:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- *
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}`, this.baseUrl);
- url.searchParams.set("state", state);
- url.searchParams.set("code", code);
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- redirect: "manual",
- });
-
- switch (resp.status) {
- case HttpStatusCode.SeeOther:
- return opEmptySuccess();
- case HttpStatusCode.NotFound:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- //
- // AML operations
- //
-
- /**
- *
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-measures
- *
- */
- async getAmlMeasures(auth: OfficerAccount) {
- const url = new URL(`aml/${auth.id}/measures`, this.baseUrl);
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- headers: {
- "Taler-AML-Officer-Signature": encodeCrock(
- signAmlQuery(auth.signingKey),
- ),
- },
- });
-
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForAvailableMeasureSummary());
- case HttpStatusCode.Conflict:
- case HttpStatusCode.NotFound:
- case HttpStatusCode.Forbidden:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- *
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-measures
- *
- */
- async getAmlKycStatistics(
- auth: OfficerAccount,
- name: string,
- filter: {
- since?: AbsoluteTime;
- until?: AbsoluteTime;
- } = {},
- ) {
- const url = new URL(`aml/${auth.id}/kyc-statistics/${name}`, this.baseUrl);
-
- if (filter.since !== undefined && filter.since.t_ms !== "never") {
- url.searchParams.set("start_date", String(filter.since.t_ms));
- }
- if (filter.until !== undefined && filter.until.t_ms !== "never") {
- url.searchParams.set("end_date", String(filter.until.t_ms));
- }
-
- const resp = await this.httpLib.fetch(url.href, {
- method: "GET",
- headers: {
- "Taler-AML-Officer-Signature": encodeCrock(
- signAmlQuery(auth.signingKey),
- ),
- },
- });
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForEventCounter());
- case HttpStatusCode.Conflict:
- case HttpStatusCode.NotFound:
- case HttpStatusCode.Forbidden:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- *
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;
- } = {},
- ) {
- const url = new URL(`aml/${auth.id}/decisions`, this.baseUrl);
-
- addPaginationParams(url, params);
- if (params.account !== undefined) {
- url.searchParams.set("h_payto", params.account);
- }
- if (params.active !== undefined) {
- url.searchParams.set("active", params.active ? "YES" : "NO");
- }
- if (params.investigation !== undefined) {
- url.searchParams.set(
- "investigation",
- params.investigation ? "YES" : "NO",
- );
- }
-
- const resp = await this.httpLib.fetch(url.href, {
- headers: {
- "Taler-AML-Officer-Signature": encodeCrock(
- signAmlQuery(auth.signingKey),
- ),
- },
- });
-
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForAmlDecisionsResponse());
- case HttpStatusCode.NoContent:
- return opFixedSuccess({ records: [] });
- case HttpStatusCode.Forbidden:
- case HttpStatusCode.NotFound:
- case HttpStatusCode.Conflict:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- *
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-decisions
- *
- */
- async getAmlLegitimizations(args: {
- officerAcc: OfficerAccount;
- }): Promise<OperationOk<LegitimizationMeasuresList>> {
- const url = new URL(
- `aml/${args.officerAcc.id}/legitimizations`,
- this.baseUrl,
- );
-
- const resp = await this.httpLib.fetch(url.href, {
- headers: {
- "Taler-AML-Officer-Signature": encodeCrock(
- signAmlQuery(args.officerAcc.signingKey),
- ),
- },
- });
-
- switch (resp.status) {
- case HttpStatusCode.Ok:
- // FIXME: Parse properly.
- return opSuccessFromHttp(resp, codecForAny());
- case HttpStatusCode.NoContent:
- return opFixedSuccess({
- measures: [],
- });
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- *
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-attributes-$H_PAYTO
- *
- */
- async getAmlAttributesForAccount(
- auth: OfficerAccount,
- account: string,
- params: PaginationParams = {},
- ) {
- const url = new URL(`aml/${auth.id}/attributes/${account}`, this.baseUrl);
-
- addPaginationParams(url, params);
- const resp = await this.httpLib.fetch(url.href, {
- headers: {
- "Taler-AML-Officer-Signature": encodeCrock(
- signAmlQuery(auth.signingKey),
- ),
- },
- });
-
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForAmlKycAttributes());
- case HttpStatusCode.NoContent:
- return opFixedSuccess({ details: [] });
- case HttpStatusCode.Forbidden:
- case HttpStatusCode.NotFound:
- case HttpStatusCode.Conflict:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- *
https://docs.taler.net/core/api-exchange.html#post--aml-$OFFICER_PUB-decision
- *
- */
- async makeAmlDesicion(
- auth: OfficerAccount,
- decision: Omit<AmlDecisionRequest, "officer_sig">,
- ) {
- const body: AmlDecisionRequest = {
- officer_sig: encodeCrock(
- signAmlDecision(auth.signingKey, decision),
- ) as EddsaSignatureString,
- ...decision,
- };
- const url = new URL(`aml/${auth.id}/decision`, this.baseUrl);
-
- const resp = await this.httpLib.fetch(url.href, {
- method: "POST",
- headers: {
- "Taler-AML-Officer-Signature": encodeCrock(
- signAmlQuery(auth.signingKey),
- ),
- },
- body,
- compress: this.preventCompression ? undefined : "deflate",
- });
-
- switch (resp.status) {
- case HttpStatusCode.NoContent: {
- this.cacheEvictor.notifySuccess(
- TalerExchangeCacheEviction.MAKE_AML_DECISION,
- );
- return opEmptySuccess();
- }
- case HttpStatusCode.Forbidden:
- case HttpStatusCode.NotFound:
- case HttpStatusCode.Conflict:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- *
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-transfers-credit
- *
- */
- async getTransfersCredit(
- auth: OfficerAccount,
- params: PaginationParams & { threshold?: AmountJson } = {},
- ) {
- const url = new URL(`aml/${auth.id}/transfers-credit`, this.baseUrl);
-
- addPaginationParams(url, params);
-
- if (params.threshold) {
- url.searchParams.set("threshold", Amounts.stringify(params.threshold));
- }
-
- const resp = await this.httpLib.fetch(url.href, {
- headers: {
- "Taler-AML-Officer-Signature": encodeCrock(
- signAmlQuery(auth.signingKey),
- ),
- },
- });
-
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForExchangeTransferList());
- case HttpStatusCode.NoContent:
- return opFixedSuccess({ transfers: [] });
- case HttpStatusCode.Forbidden:
- case HttpStatusCode.NotFound:
- case HttpStatusCode.Conflict:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-
- /**
- *
https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-transfers-debit
- *
- */
- async getTransfersDebit(
- auth: OfficerAccount,
- params: PaginationParams & { threshold?: AmountJson } = {},
- ) {
- const url = new URL(`aml/${auth.id}/transfers-debit`, this.baseUrl);
-
- addPaginationParams(url, params);
-
- if (params.threshold) {
- url.searchParams.set("threshold", Amounts.stringify(params.threshold));
- }
-
- const resp = await this.httpLib.fetch(url.href, {
- headers: {
- "Taler-AML-Officer-Signature": encodeCrock(
- signAmlQuery(auth.signingKey),
- ),
- },
- });
-
- switch (resp.status) {
- case HttpStatusCode.Ok:
- return opSuccessFromHttp(resp, codecForExchangeTransferList());
- case HttpStatusCode.NoContent:
- return opFixedSuccess({ transfers: [] });
- case HttpStatusCode.Forbidden:
- case HttpStatusCode.NotFound:
- case HttpStatusCode.Conflict:
- return opKnownHttpFailure(resp.status, resp);
- default:
- return opUnknownHttpFailure(resp);
- }
- }
-}
diff --git a/packages/taler-util/src/http-client/officer-account.ts
b/packages/taler-util/src/http-client/officer-account.ts
index f6bee214d..19128393d 100644
--- a/packages/taler-util/src/http-client/officer-account.ts
+++ b/packages/taler-util/src/http-client/officer-account.ts
@@ -21,7 +21,6 @@ import {
OfficerAccount,
OfficerId,
ReserveAccount,
- ReservePub,
createEddsaKeyPair,
decodeCrock,
decryptWithDerivedKey,
@@ -30,7 +29,7 @@ import {
encryptWithDerivedKey,
getRandomBytes,
kdf,
- stringToBytes
+ stringToBytes,
} from "@gnu-taler/taler-util";
/**
@@ -112,21 +111,25 @@ export async function createNewWalletKycAccount(
): Promise<ReserveAccount & { safe?: LockedAccount }> {
const { eddsaPriv, eddsaPub } = createEddsaKeyPair();
- const mergedRnd: EncryptionNonceP = extraNonce && password
- ? kdf(24, stringToBytes("aml-officer"), extraNonce, getRandomBytes(24))
- : getRandomBytes(24);
+ const mergedRnd: EncryptionNonceP =
+ extraNonce && password
+ ? kdf(24, stringToBytes("aml-officer"), extraNonce, getRandomBytes(24))
+ : getRandomBytes(24);
-
- const protectedPrivKey = password ? await encryptWithDerivedKey(
- mergedRnd,
- stringToBytes(password),
- eddsaPriv,
- password,
- ) : undefined;
+ const protectedPrivKey = password
+ ? await encryptWithDerivedKey(
+ mergedRnd,
+ stringToBytes(password),
+ eddsaPriv,
+ password,
+ )
+ : undefined;
const signingKey = eddsaPriv as EddsaPrivP;
- const accountId = encodeCrock(eddsaPub) as ReservePub;
- const safe = protectedPrivKey ? encodeCrock(protectedPrivKey) as
LockedAccount : undefined;
+ const accountId = encodeCrock(eddsaPub);
+ const safe = protectedPrivKey
+ ? (encodeCrock(protectedPrivKey) as LockedAccount)
+ : undefined;
return { id: accountId, signingKey, safe };
}
diff --git a/packages/taler-util/src/index.ts b/packages/taler-util/src/index.ts
index c19a5208c..6be513afc 100644
--- a/packages/taler-util/src/index.ts
+++ b/packages/taler-util/src/index.ts
@@ -16,7 +16,6 @@ export * from "./http-client/bank-integration.js";
export * from "./http-client/bank-revenue.js";
export * from "./http-client/bank-wire.js";
export * from "./http-client/challenger.js";
-export * from "./http-client/exchange.js";
export * from "./http-client/exchange-client.js";
export * from "./http-client/merchant.js";
export * from "./http-client/officer-account.js";
diff --git a/packages/taler-util/src/types-taler-common.ts
b/packages/taler-util/src/types-taler-common.ts
index a20788404..14311c132 100644
--- a/packages/taler-util/src/types-taler-common.ts
+++ b/packages/taler-util/src/types-taler-common.ts
@@ -39,11 +39,10 @@ import {
codecForString,
} from "./codec.js";
import {
+ EddsaPrivP,
codecForEither,
codecForList,
codecOptional,
- EddsaPrivP,
- ReservePub,
} from "./index.js";
import {
TalerProtocolDuration,
@@ -194,11 +193,11 @@ export type AmountString =
// export type AmountString = string;
export type Base32String = string;
declare const __eddsasign_str: unique symbol;
-export type EddsaSignatureString = string;// & { [__eddsasign_str]: true };
+export type EddsaSignatureString = string; // & { [__eddsasign_str]: true };
declare const __eddsapub_str: unique symbol;
-export type EddsaPublicKeyString = string;// & { [__eddsapub_str]: true };
+export type EddsaPublicKeyString = string; // & { [__eddsapub_str]: true };
declare const __eddsapriv_str: unique symbol;
-export type EddsaPrivateKeyString = string;// & { [__eddsapriv_str]: true };
+export type EddsaPrivateKeyString = string; // & { [__eddsapriv_str]: true };
export type CoinPublicKeyString = string;
// FIXME: implement this codec
@@ -210,11 +209,14 @@ export const codecForCurrencyName = codecForString;
// FIXME: implement this codec
export const codecForDecimalNumber = codecForString;
// FIXME: implement this codec
-export const codecForEddsaPublicKey = codecForString as () =>
Codec<EddsaPublicKeyString>;
+export const codecForEddsaPublicKey =
+ codecForString as () => Codec<EddsaPublicKeyString>;
// FIXME: implement this codec
-export const codecForEddsaPrivateKey = codecForString as () =>
Codec<EddsaPrivateKeyString>;
+export const codecForEddsaPrivateKey =
+ codecForString as () => Codec<EddsaPrivateKeyString>;
// FIXME: implement this codec
-export const codecForEddsaSignature = codecForString as () =>
Codec<EddsaSignatureString>;
+export const codecForEddsaSignature =
+ codecForString as () => Codec<EddsaSignatureString>;
export const codecForInternationalizedString =
(): Codec<InternationalizedString> => codecForMap(codecForString());
@@ -359,7 +361,11 @@ export const codecForCoinHistoryResponse = () =>
.build("CoinHistoryResponse");
export type TokenScope = BankTokenScope | MerchantTokenScope;
-export type BankTokenScope = "readonly" | "readwrite" | "revenue" |
"wiregateway";
+export type BankTokenScope =
+ | "readonly"
+ | "readwrite"
+ | "revenue"
+ | "wiregateway";
export type MerchantTokenScope = "write";
export interface TokenRequest {
// Service-defined scope for the token.
@@ -567,7 +573,7 @@ export interface OfficerAccount {
}
export interface ReserveAccount {
- id: ReservePub;
+ id: EddsaPublicKeyString;
signingKey: EddsaPrivP;
}
diff --git a/packages/taler-util/src/types-taler-exchange.ts
b/packages/taler-util/src/types-taler-exchange.ts
index 73f696839..03c6d89c5 100644
--- a/packages/taler-util/src/types-taler-exchange.ts
+++ b/packages/taler-util/src/types-taler-exchange.ts
@@ -2014,6 +2014,9 @@ export interface KycProcessClientInformation {
voluntary_measures?: KycRequirementInformation[];
}
+export type KycProcessClientInformationWithEtag =
+ KycProcessClientInformation & { etag: string | undefined };
+
declare const opaque_brand: unique symbol;
declare const opaque_kycReq: unique symbol;
diff --git a/packages/taler-wallet-core/src/dbless.ts
b/packages/taler-wallet-core/src/dbless.ts
index 01920d3aa..35cddb50f 100644
--- a/packages/taler-wallet-core/src/dbless.ts
+++ b/packages/taler-wallet-core/src/dbless.ts
@@ -39,7 +39,7 @@ import {
ExchangeRefreshRevealRequestV2,
Logger,
TalerCorebankApiClient,
- TalerExchangeHttpClient2,
+ TalerExchangeHttpClient,
UnblindedDenominationSignature,
codecForAny,
codecForBankWithdrawalOperationPostResponse,
@@ -147,7 +147,7 @@ export async function withdrawCoin(args: {
secretSeed: encodeCrock(getRandomBytes(32)),
value: Amounts.parseOrThrow(denom.value),
});
- const exchangeClient = new TalerExchangeHttpClient2(exchangeBaseUrl);
+ const exchangeClient = new TalerExchangeHttpClient(exchangeBaseUrl);
const sigResp = await cryptoApi.signWithdrawal({
amount: Amounts.stringify(denom.value),
@@ -323,7 +323,7 @@ export async function refreshCoin(req: {
logger.info(`requesting melt: ${j2s(meltReqBody)}`);
- const exchangeClient = new TalerExchangeHttpClient2(oldCoin.exchangeBaseUrl);
+ const exchangeClient = new TalerExchangeHttpClient(oldCoin.exchangeBaseUrl);
const meltResponse = succeedOrThrow(
await exchangeClient.postMelt({ body: meltReqBody }),
diff --git a/packages/taler-wallet-core/src/versions.ts
b/packages/taler-wallet-core/src/versions.ts
index ab83a7fb6..ed94da138 100644
--- a/packages/taler-wallet-core/src/versions.ts
+++ b/packages/taler-wallet-core/src/versions.ts
@@ -14,7 +14,7 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { TalerExchangeHttpClient2 } from "@gnu-taler/taler-util";
+import { TalerExchangeHttpClient } from "@gnu-taler/taler-util";
/**
* Protocol version spoken with the exchange.
@@ -22,7 +22,7 @@ import { TalerExchangeHttpClient2 } from
"@gnu-taler/taler-util";
* Uses libtool's current:revision:age versioning.
*/
export const WALLET_EXCHANGE_PROTOCOL_VERSION =
- TalerExchangeHttpClient2.SUPPORTED_EXCHANGE_PROTOCOL_VERSION;
+ TalerExchangeHttpClient.SUPPORTED_EXCHANGE_PROTOCOL_VERSION;
/**
* Protocol version spoken with the merchant.
diff --git a/packages/taler-wallet-core/src/wallet.ts
b/packages/taler-wallet-core/src/wallet.ts
index 4b2872f9c..1fb5a24d9 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -113,7 +113,7 @@ import {
TalerBankIntegrationHttpClient,
TalerError,
TalerErrorCode,
- TalerExchangeHttpClient2,
+ TalerExchangeHttpClient,
TalerMerchantInstanceHttpClient,
TalerProtocolTimestamp,
TalerUriAction,
@@ -427,8 +427,8 @@ export interface WalletExecutionContext {
export function walletExchangeClient(
baseUrl: string,
wex: WalletExecutionContext,
-): TalerExchangeHttpClient2 {
- return new TalerExchangeHttpClient2(baseUrl, {
+): TalerExchangeHttpClient {
+ return new TalerExchangeHttpClient(baseUrl, {
httpClient: wex.http,
cancelationToken: wex.cancellationToken,
longPollQueue: wex.ws.longpollQueue,
diff --git a/packages/web-util/src/context/exchange-api.ts
b/packages/web-util/src/context/exchange-api.ts
index eb839a534..52f46859a 100644
--- a/packages/web-util/src/context/exchange-api.ts
+++ b/packages/web-util/src/context/exchange-api.ts
@@ -246,7 +246,7 @@ function buildExchangeApiClient(
return {
getRemoteConfig,
- VERSION: TalerExchangeHttpClient.PROTOCOL_VERSION,
+ VERSION: TalerExchangeHttpClient.SUPPORTED_EXCHANGE_PROTOCOL_VERSION,
lib: {
exchange: ex,
},
diff --git a/packages/web-util/src/hooks/useAsync.ts
b/packages/web-util/src/hooks/useAsync.ts
index 51e89cb18..bb685d9da 100644
--- a/packages/web-util/src/hooks/useAsync.ts
+++ b/packages/web-util/src/hooks/useAsync.ts
@@ -13,8 +13,8 @@
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 { opUnknownFailure } from "@gnu-taler/taler-util";
import { useEffect, useState } from "preact/hooks";
-import { opFixedSuccess, opUnknownFailure } from "@gnu-taler/taler-util";
/**
* convert the async function into preact hook
@@ -57,10 +57,10 @@ export function useAsync<Res>(
* First start with `first` value
* Check if the it should do long-polling with `shouldRetryFn`
* Call `retryFn` if is required, long poll is expected for this function
- *
- * If `retryFn` returns faster than `minTime` (by error or because server
+ *
+ * If `retryFn` returns faster than `minTime` (by error or because server
* returned a response faster) then wait until `minTime`
- *
+ *
* @param fetcher fetcher should be a memoized function
* @param retry
* @param deps
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-typescript-core] branch master updated: unify diverged exchange clients,
Admin <=