[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-wallet-core] branch master updated (682c7847e -> 94cb65802)
From: |
gnunet |
Subject: |
[taler-wallet-core] branch master updated (682c7847e -> 94cb65802) |
Date: |
Tue, 27 Aug 2024 23:21:39 +0200 |
This is an automated email from the git hooks/post-receive script.
sebasjm pushed a change to branch master
in repository wallet-core.
from 682c7847e bump version to 0.13.0
new 3e834cd10 fix signature
new 94cb65802 freeze account
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../aml-backoffice-ui/src/ExchangeAmlFrame.tsx | 9 +-
packages/aml-backoffice-ui/src/Routing.tsx | 17 +-
packages/aml-backoffice-ui/src/hooks/decisions.ts | 12 +-
.../aml-backoffice-ui/src/pages/CaseDetails.tsx | 421 +++++++++++++++++++--
packages/aml-backoffice-ui/src/pages/Cases.tsx | 89 ++---
packages/taler-util/src/http-client/exchange.ts | 16 +-
6 files changed, 462 insertions(+), 102 deletions(-)
diff --git a/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
b/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
index 7dc36e7f6..44cd0ce82 100644
--- a/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
+++ b/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
@@ -33,7 +33,7 @@ import {
getLabelForPreferences,
usePreferences,
} from "./hooks/preferences.js";
-import { HomeIcon } from "./pages/Cases.js";
+import { HomeIcon, PeopleIcon, ToInvestigateIcon } from "./pages/Cases.js";
/**
* mapping route to view
@@ -208,7 +208,7 @@ export function ExchangeAmlFrame({
<div class="-mt-32 flex grow ">
{officer?.state !== "ready" ? undefined : <Navigation />}
<div class="flex mx-auto my-4">
- <main class="rounded-lg bg-white px-5 py-6 shadow">{children}</main>
+ <main class="block rounded-lg bg-white px-5 py-6 shadow "
style={{minWidth: 300}} >{children}</main>
</div>
</div>
@@ -224,8 +224,9 @@ export function ExchangeAmlFrame({
function Navigation(): VNode {
const { i18n } = useTranslationContext();
const pageList = [
- { route: privatePages.account, Icon: HomeIcon, label: i18n.str`Account` },
- { route: privatePages.cases, Icon: HomeIcon, label: i18n.str`Cases` },
+ { route: privatePages.profile, Icon: PeopleIcon, label: i18n.str`Profile`
},
+ { route: privatePages.investigation, Icon: ToInvestigateIcon, label:
i18n.str`Investigation` },
+ { route: privatePages.active, Icon: HomeIcon, label: i18n.str`Active` },
];
const { path } = useNavigationContext();
return (
diff --git a/packages/aml-backoffice-ui/src/Routing.tsx
b/packages/aml-backoffice-ui/src/Routing.tsx
index 4000cac00..082dc8ab5 100644
--- a/packages/aml-backoffice-ui/src/Routing.tsx
+++ b/packages/aml-backoffice-ui/src/Routing.tsx
@@ -94,8 +94,9 @@ function PublicRounting(): VNode {
}
export const privatePages = {
- account: urlPattern(/\/account/, () => "#/account"),
- cases: urlPattern(/\/cases/, () => "#/cases"),
+ profile: urlPattern(/\/profile/, () => "#/profile"),
+ investigation: urlPattern(/\/investigation/, () => "#/investigation"),
+ active: urlPattern(/\/active/, () => "#/active"),
caseUpdate: urlPattern<{ cid: string; type: string }>(
/\/case\/(?<cid>[a-zA-Z0-9]+)\/new\/(?<type>[a-zA-Z0-9_.]+)/,
({ cid, type }) => `#/case/${cid}/new/${type}`,
@@ -114,8 +115,9 @@ function PrivateRouting(): VNode {
const { navigateTo } = useNavigationContext();
const location = useCurrentLocation(privatePages);
useEffect(() => {
- if (location === undefined) {
- navigateTo(privatePages.account.url({}));
+ if (location.name === undefined) {
+ console.log("asd")
+ navigateTo(privatePages.profile.url({}));
}
}, [location]);
@@ -123,7 +125,7 @@ function PrivateRouting(): VNode {
case undefined: {
return <Fragment />;
}
- case "account": {
+ case "profile": {
return <Officer />;
}
case "caseDetails": {
@@ -137,7 +139,10 @@ function PrivateRouting(): VNode {
case "caseNew": {
return <SelectForm account={location.values.cid} />;
}
- case "cases": {
+ case "investigation": {
+ return <Cases filtered/>;
+ }
+ case "active": {
return <Cases />;
}
default:
diff --git a/packages/aml-backoffice-ui/src/hooks/decisions.ts
b/packages/aml-backoffice-ui/src/hooks/decisions.ts
index e652f233e..de8f1637e 100644
--- a/packages/aml-backoffice-ui/src/hooks/decisions.ts
+++ b/packages/aml-backoffice-ui/src/hooks/decisions.ts
@@ -37,7 +37,7 @@ export const PAGINATED_LIST_REQUEST = PAGINATED_LIST_SIZE + 1;
* @param args
* @returns
*/
-export function useCurrentDecisions() {
+export function useCurrentDecisions(filtered?: boolean) {
const officer = useOfficer();
const session = officer.state === "ready" ? officer.account : undefined;
const {
@@ -46,13 +46,15 @@ export function useCurrentDecisions() {
const [offset, setOffset] = useState<string>();
- async function fetcher([officer, offset]: [
+ async function fetcher([officer, offset, investigation]: [
OfficerAccount,
string | undefined,
+ boolean | undefined
]) {
return await api.getAmlDecisions(officer, {
- order: "asc",
+ order: "dec",
offset,
+ investigation,
active: true,
limit: PAGINATED_LIST_REQUEST,
});
@@ -62,7 +64,7 @@ export function useCurrentDecisions() {
TalerExchangeResultByMethod<"getAmlDecisions">,
TalerHttpError
>(
- !session ? undefined : [session, offset, "getAmlDecisions"],
+ !session ? undefined : [session, offset, filtered ? true : filtered,
"getAmlDecisions"],
fetcher,
);
@@ -95,7 +97,7 @@ export function useAccountDecisions(accountStr: string) {
string | undefined,
]) {
return await api.getAmlDecisions(officer, {
- order: "asc",
+ order: "dec",
offset,
account,
limit: PAGINATED_LIST_REQUEST,
diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
index b26e6f430..b421bd8c5 100644
--- a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
+++ b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
@@ -51,6 +51,7 @@ import { preloadedForms } from "../forms/index.js";
import { useAccountInformation } from "../hooks/account.js";
import { useAccountDecisions } from "../hooks/decisions.js";
import { ShowConsolidated } from "./ShowConsolidated.js";
+import { useOfficer } from "../hooks/officer.js";
export type AmlEvent =
| AmlFormEvent
@@ -175,6 +176,10 @@ export function CaseDetails({ account }: { account: string
}) {
justification: Justification;
metadata: FormMetadata;
}>();
+ const { config, lib } = useExchangeApiContext()
+ const officer = useOfficer();
+ const session = officer.state === "ready" ? officer.account : undefined;
+
const { i18n } = useTranslationContext();
const details = useAccountInformation(account);
@@ -215,7 +220,8 @@ export function CaseDetails({ account }: { account: string
}) {
}
}
const { details: accountDetails } = details.body;
- const activeDesicion = history.body.find(d => d.is_active)
+ const activeDecision = history.body.find(d => d.is_active)
+ const restDecisions = !activeDecision ? history.body : history.body.filter(d
=> d.rowid !== activeDecision.rowid)
const events = getEventsFromAmlHistory(
accountDetails,
@@ -243,30 +249,9 @@ export function CaseDetails({ account }: { account: string
}) {
</DefaultForm>
);
}
- return (
- <div>
- <a
- // href={privatePages.caseNew.url({ cid: account })}
- href="#"
- class="m-4 block 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"
- >
- <i18n.Translate>Freeze account</i18n.Translate>
- </a>
- <a
- // href={privatePages.caseNew.url({ cid: account })}
- href="#"
- class="m-4 block 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"
- >
- <i18n.Translate>New threshold</i18n.Translate>
- </a>
- <a
- // href={privatePages.caseNew.url({ cid: account })}
- href="#"
- class="m-4 block 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"
- >
- <i18n.Translate>Ask more information</i18n.Translate>
- </a>
+ return (
+ <div class="min-w-60">
<header class="flex items-center justify-between border-b border-white/5
px-4 py-4 sm:px-6 sm:py-6 lg:px-8">
<h1 class="text-base font-semibold leading-7 text-black">
<i18n.Translate>
@@ -275,10 +260,112 @@ export function CaseDetails({ account }: { account:
string }) {
</i18n.Translate>
</h1>
</header>
- {!activeDesicion ? <Attention title={i18n.str`No active decision found`}
type="warning" /> : <Fragment>
- {!activeDesicion.to_investigate ? undefined : <Attention
title={i18n.str`Requires investigation`} type="warning" />}
- <ShowActiveDecision decision={activeDesicion} />
+
+ {!activeDecision || !activeDecision.to_investigate ? undefined :
<Attention title={i18n.str`Under investigation`} type="warning" >
+ <i18n.Translate>This account requires a manual review and is waiting
for a decision to be made.</i18n.Translate>
+ </Attention>}
+
+ <div>
+ <button
+ onClick={async () => {
+ if (!session) return;
+ lib.exchange.makeAmlDesicion(session, {
+ decision_time:
AbsoluteTime.toProtocolTimestamp(AbsoluteTime.now()),
+ h_payto: account,
+ justification: "",
+ keep_investigating: false,
+ properties: {},
+ new_rules: {
+ custom_measures: {},
+ expiration_time:
AbsoluteTime.toProtocolTimestamp(AbsoluteTime.never()),
+ rules: FREEZE_RULES(config.currency),
+ successor_measure: "verboten",
+ },
+ })
+ }}
+ 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"
+ >
+ <i18n.Translate>Freeze account</i18n.Translate>
+ </button>
+ <button
+ onClick={async () => {
+ if (!session) return;
+ lib.exchange.makeAmlDesicion(session, {
+ decision_time:
AbsoluteTime.toProtocolTimestamp(AbsoluteTime.now()),
+ h_payto: account,
+ justification: "",
+ keep_investigating: false,
+ properties: {},
+ new_rules: {
+ custom_measures: {},
+ expiration_time:
AbsoluteTime.toProtocolTimestamp(AbsoluteTime.never()),
+ rules: THRESHOLD_100_HOUR(config.currency),
+ successor_measure: "verboten",
+ },
+ })
+ }}
+
+ 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"
+ >
+ <i18n.Translate>Set threshold to 100 / hour</i18n.Translate>
+ </button>
+ <button
+ onClick={async () => {
+ if (!session) return;
+ lib.exchange.makeAmlDesicion(session, {
+ decision_time:
AbsoluteTime.toProtocolTimestamp(AbsoluteTime.now()),
+ h_payto: account,
+ justification: "",
+ keep_investigating: false,
+ properties: {},
+ new_rules: {
+ custom_measures: {},
+ expiration_time:
AbsoluteTime.toProtocolTimestamp(AbsoluteTime.never()),
+ rules: THRESHOLD_2000_WEEK(config.currency),
+ successor_measure: "verboten",
+ },
+ })
+ }}
+
+ 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"
+ >
+ <i18n.Translate>Set threshold to 2000 / week</i18n.Translate>
+ </button>
+ <button
+ onClick={async () => {
+ if (!session) return;
+ lib.exchange.makeAmlDesicion(session, {
+ decision_time:
AbsoluteTime.toProtocolTimestamp(AbsoluteTime.now()),
+ h_payto: account,
+ justification: "",
+ keep_investigating: false,
+ properties: {},
+ new_measure: "onlyTalers",
+ new_rules: {
+ custom_measures: {},
+ expiration_time:
AbsoluteTime.toProtocolTimestamp(AbsoluteTime.never()),
+ rules: FREEZE_RULES(config.currency),
+ successor_measure: "verboten",
+ },
+ })
+ }}
+
+ 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"
+ >
+ <i18n.Translate>Ask for more information</i18n.Translate>
+ </button>
+ </div>
+
+ {!activeDecision ? <Attention title={i18n.str`No active decision found`}
type="warning" /> : <Fragment>
+ <h1 class="my-4 text-base font-semibold leading-6 text-black">
+ <i18n.Translate>Current active rules</i18n.Translate>
+ </h1>
+
+ <ShowDecisionInfo decision={activeDecision} />
</Fragment>}
+ <h1 class="my-4 text-base font-semibold leading-6 text-black">
+ <i18n.Translate>KYC collection events</i18n.Translate>
+ </h1>
<ShowTimeline
history={events}
onSelect={(e) => {
@@ -299,25 +386,55 @@ export function CaseDetails({ account }: { account:
string }) {
/>
{/* {selected && <ShowEventDetails event={selected} />} */}
{selected && <ShowConsolidated history={events} until={selected} />}
+ {restDecisions.length > 0 ?
+ <Fragment>
+ <h1 class="my-4 text-base font-semibold leading-6 text-black">
+ <i18n.Translate>Previous AML decisions</i18n.Translate>
+ </h1>
+ {restDecisions.map(d => {
+ return <ShowDecisionInfo decision={d} />
+ })}
+
+ </Fragment> : <div />}
</div>
);
}
-function ShowActiveDecision({ decision }: { decision:
TalerExchangeApi.AmlDecision }): VNode {
+function ShowDecisionInfo({ decision }: { decision:
TalerExchangeApi.AmlDecision }): VNode {
const { i18n } = useTranslationContext();
const { config } = useExchangeApiContext()
return <Fragment>
- <h1 class="mt-4 text-base font-semibold leading-6 text-black">
- <i18n.Translate>Current active rules</i18n.Translate>
- </h1>
<div class="sm:col-span-5">
<label
for="amount"
class="block text-sm font-medium leading-6 text-gray-900"
>
- <b>Expiration time</b>
+ <b><i18n.Translate>Since</i18n.Translate></b>
+ <div class="flex rounded-md shadow-sm border-0 ring-1 ring-inset
ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
+
+ <div
+ class="p-4 disabled:bg-gray-200 rounded-md rounded-l-none
data-[left=true]:text-left w-full py-1.5 pl-3 text-gray-900
placeholder:text-gray-400 sm:text-sm sm:leading-6"
+ >
+
+ <Time format="dd/MM/yyyy HH:mm:ss"
timestamp={AbsoluteTime.fromProtocolTimestamp(decision.decision_time)} />
+ </div>
+ </div>
+
+
+ </label>
+ </div>
+
+ <div class="sm:col-span-5">
+ <label
+ for="amount"
+ class="block text-sm font-medium leading-6 text-gray-900"
+ >
+
{AbsoluteTime.isExpired(AbsoluteTime.fromProtocolTimestamp(decision.limits.expiration_time))
?
+ <b><i18n.Translate>Expired at</i18n.Translate></b> :
+ <b><i18n.Translate>Expires at</i18n.Translate></b>
+ }
<div class="flex rounded-md shadow-sm border-0 ring-1 ring-inset
ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
<div
@@ -631,3 +748,243 @@ function parseJustification(
};
}
}
+
+const THRESHOLD_2000_WEEK: (currency: string) => TalerExchangeApi.KycRule[] =
(currency) => [{
+ "operation_type": "WITHDRAW",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "DEPOSIT",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "AGGREGATE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "MERGE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "BALANCE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "CLOSE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+}]
+
+const THRESHOLD_100_HOUR: (currency: string) => TalerExchangeApi.KycRule[] =
(currency) => [{
+ "operation_type": "WITHDRAW",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "DEPOSIT",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "AGGREGATE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "MERGE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "BALANCE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "CLOSE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+}]
+
+
+
+const FREEZE_RULES: (currency: string) => TalerExchangeApi.KycRule[] =
(currency) => [{
+ "operation_type": "WITHDRAW",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "DEPOSIT",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "AGGREGATE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "MERGE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "BALANCE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+},
+{
+ "operation_type": "CLOSE",
+ "threshold": `${currency}:0`,
+ "timeframe": {
+ "d_us": "forever"
+ },
+ "measures": [
+ "verboten"
+ ],
+ "display_priority": 1,
+ "exposed": true,
+ "is_and_combinator": true
+}]
+
diff --git a/packages/aml-backoffice-ui/src/pages/Cases.tsx
b/packages/aml-backoffice-ui/src/pages/Cases.tsx
index 9a569cd60..d79ce9006 100644
--- a/packages/aml-backoffice-ui/src/pages/Cases.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Cases.tsx
@@ -36,6 +36,7 @@ import { FormErrors, RecursivePartial, useFormState } from
"../hooks/form.js";
import { undefinedIfEmpty } from "./CreateAccount.js";
import { Officer } from "./Officer.js";
import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js";
+import { useState } from "preact/hooks";
type FormType = {
// state: TalerExchangeApi.AmlState;
@@ -43,15 +44,13 @@ type FormType = {
export function CasesUI({
records,
- // filter,
- // onChangeFilter,
onFirstPage,
onNext,
+ filtered,
}: {
+ filtered: boolean,
onFirstPage?: () => void;
onNext?: () => void;
- // filter: TalerExchangeApi.AmlState;
- // onChangeFilter: (f: TalerExchangeApi.AmlState) => void;
records: TalerExchangeApi.AmlDecision[];
}): VNode {
const { i18n } = useTranslationContext();
@@ -94,38 +93,27 @@ export function CasesUI({
return (
<div>
<div class="sm:flex sm:items-center">
- <div class="px-2 sm:flex-auto">
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Cases</i18n.Translate>
- </h1>
- <p class="mt-2 text-sm text-gray-700 w-80">
- <i18n.Translate>
- A list of all the account with the status
- </i18n.Translate>
- </p>
- </div>
- <div class="px-2">
- {/* <InputChoiceHorizontal<FormType, "state">
- name="state"
- label={i18n.str`Filter`}
- handler={form.state}
- converter={amlStateConverter}
- choices={[
- {
- label: i18n.str`Pending`,
- value: "pending",
- },
- {
- label: i18n.str`Frozen`,
- value: "frozen",
- },
- {
- label: i18n.str`Normal`,
- value: "normal",
- },
- ]}
- /> */}
- </div>
+ {filtered ?
+ <div class="px-2 sm:flex-auto">
+ <h1 class="text-base font-semibold leading-6 text-gray-900">
+ <i18n.Translate>Cases under investigation</i18n.Translate>
+ </h1>
+ <p class="mt-2 text-sm text-gray-700 w-80">
+ <i18n.Translate>
+ A list of all the accounts which are waiting for a deicison to
be made.
+ </i18n.Translate>
+ </p>
+ </div> : <div class="px-2 sm:flex-auto">
+ <h1 class="text-base font-semibold leading-6 text-gray-900">
+ <i18n.Translate>Cases</i18n.Translate>
+ </h1>
+ <p class="mt-2 text-sm text-gray-700 w-80">
+ <i18n.Translate>
+ A list of all the known account by the exchange.
+ </i18n.Translate>
+ </p>
+ </div>
+ }
</div>
<div class="mt-8 flow-root">
<div class="overflow-x-auto">
@@ -167,7 +155,7 @@ export function CasesUI({
</div>
</td>
<td class="whitespace-nowrap px-3 py-5 text-sm
text-gray-900">
- {r.to_investigate ? <ToInvestigateIcon /> :
undefined}
+ {r.to_investigate ? <span title="require
investigation"><ToInvestigateIcon /></span> : undefined}
</td>
</tr>
);
@@ -182,19 +170,9 @@ export function CasesUI({
</div>
);
}
-function ToInvestigateIcon(): VNode {
- return <svg title="requires investigation"
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" class="size-6 w-6">
- <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303
3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874
1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12
15.75h.007v.008H12v-.008Z" />
- </svg>
-}
-
-export function Cases() {
- // const [stateFilter, setStateFilter] = useState(
- // TalerExchangeApi.AmlState.pending,
- // );
-
- const list = useCurrentDecisions();
+export function Cases({ filtered }: { filtered?: boolean }) {
+ const list = useCurrentDecisions(filtered);
const { i18n } = useTranslationContext();
if (!list) {
@@ -251,6 +229,7 @@ export function Cases() {
return (
<CasesUI
+ filtered={!!filtered}
records={list.body}
onFirstPage={list.isFirstPage ? undefined : list.loadFirst}
onNext={list.isLastPage ? undefined : list.loadNext}
@@ -262,6 +241,18 @@ export function Cases() {
);
}
+// function ToInvestigateIcon(): VNode {
+// return <svg title="requires investigation"
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" class="size-6 w-6">
+// <path stroke-linecap="round" stroke-linejoin="round" d="M12
9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874
1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12
15.75h.007v.008H12v-.008Z" />
+// </svg>
+// }
+export const ToInvestigateIcon = () => (
+ <svg title="requires investigation" xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
class="size-6 w-6">
+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303
3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874
1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12
15.75h.007v.008H12v-.008Z" />
+ </svg>
+);
+
+
export const PeopleIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
diff --git a/packages/taler-util/src/http-client/exchange.ts
b/packages/taler-util/src/http-client/exchange.ts
index f82cf6608..6ab7706b5 100644
--- a/packages/taler-util/src/http-client/exchange.ts
+++ b/packages/taler-util/src/http-client/exchange.ts
@@ -22,6 +22,7 @@ import {
import { Codec, codecForAny } from "../codec.js";
import {
TalerSignaturePurpose,
+ bufferForUint64,
buildSigPS,
decodeCrock,
eddsaSign,
@@ -66,6 +67,7 @@ import {
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,
@@ -777,7 +779,7 @@ 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) {}
+ async completeExternalKycProcess(provider: string, state: string) { }
//
// AML operations
@@ -1021,16 +1023,18 @@ 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_measure != null ?
hash(stringToBytes(decision.new_measure)) : zero)
+ .put(bufferForUint64(decision.keep_investigating ? 1 : 0))
.build();
+
const officer_sig = encodeCrock(eddsaSign(sigBlob, key));
+
return {
...decision,
officer_sig,
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-wallet-core] branch master updated (682c7847e -> 94cb65802),
gnunet <=