gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] 02/02: case details and missing decision encryption


From: gnunet
Subject: [taler-wallet-core] 02/02: case details and missing decision encryption
Date: Fri, 21 Jul 2023 20:51:02 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

commit 7e37b347447b6fc418f11160d439a7596b039680
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Fri Jul 21 15:50:53 2023 -0300

    case details and missing decision encryption
---
 packages/aml-backoffice-ui/src/account.ts          |  19 ++-
 .../src/handlers/FormProvider.tsx                  |   2 +-
 packages/aml-backoffice-ui/src/hooks/useBackend.ts |   8 +-
 .../aml-backoffice-ui/src/hooks/useCaseDetails.ts  | 162 +++++++++++++++++++++
 packages/aml-backoffice-ui/src/hooks/useCases.ts   |  53 +++++++
 packages/aml-backoffice-ui/src/pages.ts            |   2 +-
 .../aml-backoffice-ui/src/pages/CaseDetails.tsx    | 131 +++++++----------
 packages/aml-backoffice-ui/src/pages/Cases.tsx     |  53 -------
 .../aml-backoffice-ui/src/pages/NewFormEntry.tsx   |  40 ++++-
 packages/aml-backoffice-ui/src/types.ts            |  36 +++++
 10 files changed, 362 insertions(+), 144 deletions(-)

diff --git a/packages/aml-backoffice-ui/src/account.ts 
b/packages/aml-backoffice-ui/src/account.ts
index 1c8cd7f53..2225bf2ff 100644
--- a/packages/aml-backoffice-ui/src/account.ts
+++ b/packages/aml-backoffice-ui/src/account.ts
@@ -1,6 +1,7 @@
 import {
-  PaytoUri,
+  Amounts,
   TalerSignaturePurpose,
+  amountToBuffer,
   bufferForUint32,
   buildSigPS,
   createEddsaKeyPair,
@@ -11,8 +12,10 @@ import {
   encodeCrock,
   encryptWithDerivedKey,
   getRandomBytesF,
+  hash,
+  hashTruncate32,
   stringToBytes,
-  stringifyPaytoUri,
+  timestampRoundedToBuffer
 } from "@gnu-taler/taler-util";
 import { AmlExchangeBackend } from "./types.js";
 
@@ -60,12 +63,16 @@ export function buildQuerySignature(key: SigningKey): 
string {
 }
 export function buildDecisionSignature(
   key: SigningKey,
-  payto: PaytoUri,
-  state: AmlExchangeBackend.AmlState,
+  decision: AmlExchangeBackend.AmlDecision,
 ): string {
+
   const sigBlob = 
buildSigPS(TalerSignaturePurpose.TALER_SIGNATURE_AML_DECISION)
-    .put(decodeCrock(stringifyPaytoUri(payto)))
-    .put(bufferForUint32(state))
+    .put(hash(stringToBytes(decision.justification)))
+    // .put(timestampRoundedToBuffer(decision.decision_time))
+    .put(amountToBuffer(decision.new_threshold))
+    .put(decodeCrock(decision.h_payto))
+    // .put(hash(stringToBytes(decision.kyc_requirements)))
+    .put(bufferForUint32(decision.new_state))
     .build();
 
   return encodeCrock(eddsaSign(sigBlob, key));
diff --git a/packages/aml-backoffice-ui/src/handlers/FormProvider.tsx 
b/packages/aml-backoffice-ui/src/handlers/FormProvider.tsx
index a195c2051..3da2a4f07 100644
--- a/packages/aml-backoffice-ui/src/handlers/FormProvider.tsx
+++ b/packages/aml-backoffice-ui/src/handlers/FormProvider.tsx
@@ -29,7 +29,7 @@ export type FormState<T> = {
     ? Partial<InputFieldState>
     : T[field] extends Array<infer P>
     ? Partial<InputArrayFieldState<P>>
-    : T[field] extends object
+    : T[field] extends (object | undefined)
     ? FormState<T[field]>
     : Partial<InputFieldState>;
 };
diff --git a/packages/aml-backoffice-ui/src/hooks/useBackend.ts 
b/packages/aml-backoffice-ui/src/hooks/useBackend.ts
index e68efb2e3..b9d66fca6 100644
--- a/packages/aml-backoffice-ui/src/hooks/useBackend.ts
+++ b/packages/aml-backoffice-ui/src/hooks/useBackend.ts
@@ -14,7 +14,7 @@ interface useBackendType {
     path: string,
     options?: RequestOptions,
   ) => Promise<HttpResponseOk<T>>;
-  fetcher: <T>(endpoint: string) => Promise<HttpResponseOk<T>>;
+  fetcher: <T>(args: [string, string]) => Promise<HttpResponseOk<T>>;
   paginatedFetcher: <T>(
     args: [string, number, number, string],
   ) => Promise<HttpResponseOk<T>>;
@@ -35,8 +35,10 @@ export function usePublicBackend(): useBackendType {
   );
 
   const fetcher = useCallback(
-    function fetcherImpl<T>(endpoint: string): Promise<HttpResponseOk<T>> {
-      return requestHandler<T>(baseUrl, endpoint);
+    function fetcherImpl<T>([endpoint, talerAmlOfficerSignature]: 
[string,string]): Promise<HttpResponseOk<T>> {
+      return requestHandler<T>(baseUrl, endpoint, {
+        talerAmlOfficerSignature
+      });
     },
     [baseUrl],
   );
diff --git a/packages/aml-backoffice-ui/src/hooks/useCaseDetails.ts 
b/packages/aml-backoffice-ui/src/hooks/useCaseDetails.ts
new file mode 100644
index 000000000..980a35f21
--- /dev/null
+++ b/packages/aml-backoffice-ui/src/hooks/useCaseDetails.ts
@@ -0,0 +1,162 @@
+
+import {
+  HttpResponse,
+  HttpResponseOk,
+  RequestError
+} from "@gnu-taler/web-util/browser";
+import { AmlExchangeBackend } from "../types.js";
+// FIX default import https://github.com/microsoft/TypeScript/issues/49189
+import _useSWR, { SWRHook, useSWRConfig } from "swr";
+import { AccountId } from "../account.js";
+import { usePublicBackend } from "./useBackend.js";
+const useSWR = _useSWR as unknown as SWRHook;
+
+export function useCaseDetails(
+  account: AccountId,
+  paytoHash: string,
+  signature: string | undefined,
+): HttpResponse<
+  AmlExchangeBackend.AmlDecisionDetails,
+  AmlExchangeBackend.AmlError
+> {
+  const { fetcher } = usePublicBackend();
+
+  const { data, error } = useSWR<
+  HttpResponseOk<AmlExchangeBackend.AmlDecisionDetails>,
+  RequestError<AmlExchangeBackend.AmlError>
+>(    [
+  `aml/${account}/decision/${(paytoHash)}`,
+  signature,
+],
+fetcher, {
+    refreshInterval: 0,
+    refreshWhenHidden: false,
+    revalidateOnFocus: false,
+    revalidateOnReconnect: false,
+    refreshWhenOffline: false,
+    errorRetryCount: 0,
+    errorRetryInterval: 1,
+    shouldRetryOnError: false,
+    keepPreviousData: true,
+  });
+
+  if (data) return data;
+  if (error) return error.cause;
+  return { loading: true };
+}
+
+const example1: AmlExchangeBackend.AmlDecisionDetails = {
+  aml_history: [
+    {
+      justification: "Lack of documentation",
+      decider_pub: "ASDASDASD",
+      decision_time: {
+        t_s: Date.now() / 1000,
+      },
+      new_state: 2,
+      new_threshold: "USD:0",
+    },
+    {
+      justification: "Doing a transfer of high amount",
+      decider_pub: "ASDASDASD",
+      decision_time: {
+        t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 6,
+      },
+      new_state: 1,
+      new_threshold: "USD:2000",
+    },
+    {
+      justification: "Account is known to the system",
+      decider_pub: "ASDASDASD",
+      decision_time: {
+        t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 9,
+      },
+      new_state: 0,
+      new_threshold: "USD:100",
+    },
+  ],
+  kyc_attributes: [
+    {
+      collection_time: {
+        t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 8,
+      },
+      expiration_time: {
+        t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 4,
+      },
+      provider_section: "asdasd",
+      attributes: {
+        name: "Sebastian",
+      },
+    },
+    {
+      collection_time: {
+        t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 5,
+      },
+      expiration_time: {
+        t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 2,
+      },
+      provider_section: "asdasd",
+      attributes: {
+        creditCard: "12312312312",
+      },
+    },
+  ],
+};
+
+export const exampleResponse: 
HttpResponse<AmlExchangeBackend.AmlDecisionDetails,AmlExchangeBackend.AmlError> 
= {
+  ok: true,
+  data: example1,
+}
+
+
+export function useAmlCasesAPI(): AmlCaseAPI {
+  const { request } = usePublicBackend();
+  const mutateAll = useMatchMutate();
+
+  const updateDecision = async (
+    officer: AccountId,
+    data: AmlExchangeBackend.AmlDecision,
+  ): Promise<HttpResponseOk<void>> => {
+    const res = await request<void>(`aml/${officer}/decision`, {
+      method: "POST",
+      data,
+      contentType: "json",
+    });
+    await mutateAll(/.*aml.*/);
+    return res;
+  };
+
+  return {
+    updateDecision,
+  };
+}
+
+export interface AmlCaseAPI {
+  updateDecision: (
+    officer: AccountId,
+    data: AmlExchangeBackend.AmlDecision,
+  ) => Promise<HttpResponseOk<void>>;
+}
+
+
+function useMatchMutate(): (
+  re: RegExp,
+  value?: unknown,
+) => Promise<any> {
+  const { cache, mutate } = useSWRConfig();
+
+  if (!(cache instanceof Map)) {
+    throw new Error(
+      "matchMutate requires the cache provider to be a Map instance",
+    );
+  }
+
+  return function matchRegexMutate(re: RegExp, value?: unknown) {
+    const allKeys = Array.from(cache.keys());
+    const keys = allKeys.filter((key) => re.test(key));
+    const mutations = keys.map((key) => {
+      return mutate(key, value, true);
+    });
+    return Promise.all(mutations);
+  };
+}
diff --git a/packages/aml-backoffice-ui/src/hooks/useCases.ts 
b/packages/aml-backoffice-ui/src/hooks/useCases.ts
index 04b7c383b..c5a0fc489 100644
--- a/packages/aml-backoffice-ui/src/hooks/useCases.ts
+++ b/packages/aml-backoffice-ui/src/hooks/useCases.ts
@@ -92,3 +92,56 @@ export function useCases(
   }
   return { loading: true };
 }
+
+const example1: AmlExchangeBackend.AmlRecords = {
+  records: [
+    {
+      current_state: 0,
+      h_payto: "QWEQWEQWEQWEWQE",
+      rowid: 1,
+      threshold: "USD 100",
+    },
+    {
+      current_state: 1,
+      h_payto: "ASDASDASD",
+      rowid: 1,
+      threshold: "USD 100",
+    },
+    {
+      current_state: 2,
+      h_payto: "ZXCZXCZXCXZC",
+      rowid: 1,
+      threshold: "USD 1000",
+    },
+    {
+      current_state: 0,
+      h_payto: "QWEQWEQWEQWEWQE",
+      rowid: 1,
+      threshold: "USD 100",
+    },
+    {
+      current_state: 1,
+      h_payto: "ASDASDASD",
+      rowid: 1,
+      threshold: "USD 100",
+    },
+    {
+      current_state: 2,
+      h_payto: "ZXCZXCZXCXZC",
+      rowid: 1,
+      threshold: "USD 1000",
+    },
+  ].map((e, idx) => {
+    e.rowid = idx;
+    e.threshold = `${e.threshold}${idx}`;
+    return e;
+  }),
+};
+
+export const exampleResponse: 
HttpResponsePaginated<AmlExchangeBackend.AmlRecords,AmlExchangeBackend.AmlError>
 = {
+  ok: true,
+  data: example1,
+  loadMore: () => {},
+  loadMorePrev: () => {},  
+}
+
diff --git a/packages/aml-backoffice-ui/src/pages.ts 
b/packages/aml-backoffice-ui/src/pages.ts
index 18fb7a158..e4e16f05f 100644
--- a/packages/aml-backoffice-ui/src/pages.ts
+++ b/packages/aml-backoffice-ui/src/pages.ts
@@ -16,7 +16,7 @@ const cases: PageEntry = {
   url: "#/cases",
   view: Cases,
 };
-const account: PageEntry<{ account?: string }> = {
+const account: PageEntry<{ account: string }> = {
   url: pageDefinition("#/account/:account"),
   view: CaseDetails,
 };
diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx 
b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
index d02d8b395..ce820d612 100644
--- a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
+++ b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
@@ -13,64 +13,13 @@ import { FlexibleForm } from "../forms/index.js";
 import { UIFormField } from "../handlers/forms.js";
 import { Pages } from "../pages.js";
 import { AmlExchangeBackend } from "../types.js";
+import { HandleAccountNotReady } from "./HandleAccountNotReady.js";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { useOfficer } from "../hooks/useOfficer.js";
+import { buildQuerySignature } from "../account.js";
+import { useCaseDetails } from "../hooks/useCaseDetails.js";
+import { handleNotOkResult } from "../utils/errors.js";
 
-const response: AmlExchangeBackend.AmlDecisionDetails = {
-  aml_history: [
-    {
-      justification: "Lack of documentation",
-      decider_pub: "ASDASDASD",
-      decision_time: {
-        t_s: Date.now() / 1000,
-      },
-      new_state: 2,
-      new_threshold: "USD:0",
-    },
-    {
-      justification: "Doing a transfer of high amount",
-      decider_pub: "ASDASDASD",
-      decision_time: {
-        t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 6,
-      },
-      new_state: 1,
-      new_threshold: "USD:2000",
-    },
-    {
-      justification: "Account is known to the system",
-      decider_pub: "ASDASDASD",
-      decision_time: {
-        t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 9,
-      },
-      new_state: 0,
-      new_threshold: "USD:100",
-    },
-  ],
-  kyc_attributes: [
-    {
-      collection_time: {
-        t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 8,
-      },
-      expiration_time: {
-        t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 4,
-      },
-      provider_section: "asdasd",
-      attributes: {
-        name: "Sebastian",
-      },
-    },
-    {
-      collection_time: {
-        t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 5,
-      },
-      expiration_time: {
-        t_s: Date.now() / 1000 - 60 * 60 * 24 * 30 * 2,
-      },
-      provider_section: "asdasd",
-      attributes: {
-        creditCard: "12312312312",
-      },
-    },
-  ],
-};
 type AmlEvent = AmlFormEvent | KycCollectionEvent | KycExpirationEvent;
 type AmlFormEvent = {
   type: "aml-form";
@@ -127,7 +76,7 @@ function getEventsFromAmlHistory(
     });
     prev.push({
       type: "kyc-expiration",
-      title: "expired" as TranslatedString,
+      title: "expiration" as TranslatedString,
       when: AbsoluteTime.fromProtocolTimestamp(k.expiration_time),
       fields: !k.attributes ? [] : Object.keys(k.attributes),
     });
@@ -136,19 +85,30 @@ function getEventsFromAmlHistory(
   return ae.concat(ke).sort(selectSooner);
 }
 
-export function CaseDetails({ account }: { account?: string }) {
-  const events = getEventsFromAmlHistory(
-    response.aml_history,
-    response.kyc_attributes,
-  );
-  console.log("DETAILS", events, events[events.length - 1 - 2]);
-  const [selected, setSelected] = useState<AmlEvent>(
-    events[events.length - 1 - 2],
-  );
+export function CaseDetails({ account: paytoHash }: { account: string }) {
+  const [selected, setSelected] = useState<AmlEvent | undefined>(undefined);
+
+  const officer = useOfficer();
+  const { i18n } = useTranslationContext();
+  if (officer.state !== "ready") {
+    return <HandleAccountNotReady officer={officer} />;
+  }
+  const signature =
+    officer.state === "ready"
+      ? buildQuerySignature(officer.account.signingKey)
+      : undefined;
+  const details = useCaseDetails(officer.account.accountId, paytoHash, 
signature)
+  if (!details.ok && !details.loading) {
+    return handleNotOkResult(i18n)(details);
+  }
+  const aml_history = details.loading ? [] : details.data.aml_history
+  const kyc_attributes = details.loading ? [] : details.data.kyc_attributes
+  const events = getEventsFromAmlHistory(aml_history,kyc_attributes);
+  
   return (
     <div>
       <a
-        href={Pages.newFormEntry.url({ account })}
+        href={Pages.newFormEntry.url({ account: paytoHash })}
         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"
       >
         New AML form
@@ -271,13 +231,24 @@ function ShowConsolidated({
   history: AmlEvent[];
   until: AmlEvent;
 }): VNode {
-  console.log("UNTIL", until);
   const cons = getConsolidated(history, until.when);
 
   const form: FlexibleForm<Consolidated> = {
     versionId: "1",
     behavior: (form) => {
-      return {};
+      return {
+        aml: {
+          threshold: {
+            hidden: !form.aml
+          },
+          since: {
+            hidden: !form.aml
+          },
+          state: {
+            hidden: !form.aml
+          }
+        }
+      };
     },
     design: [
       {
@@ -356,8 +327,8 @@ function ShowConsolidated({
 
 interface Consolidated {
   aml: {
-    state?: AmlExchangeBackend.AmlState;
-    threshold?: AmountJson;
+    state: AmlExchangeBackend.AmlState;
+    threshold: AmountJson;
     since: AbsoluteTime;
   };
   kyc: {
@@ -375,7 +346,13 @@ function getConsolidated(
 ): Consolidated {
   const initial: Consolidated = {
     aml: {
-      since: AbsoluteTime.never(),
+      state: AmlExchangeBackend.AmlState.normal,
+      threshold: {
+        currency: "ARS",
+        value: 1000,
+        fraction: 0,
+      },
+      since: AbsoluteTime.never()
     },
     kyc: {},
   };
@@ -391,9 +368,11 @@ function getConsolidated(
         break;
       }
       case "aml-form": {
-        prev.aml.threshold = cur.threshold;
-        prev.aml.state = cur.state;
-        prev.aml.since = cur.when;
+        prev.aml = {
+          since: cur.when,
+          state: cur.state,
+          threshold: cur.threshold
+        }
         break;
       }
       case "kyc-collection": {
diff --git a/packages/aml-backoffice-ui/src/pages/Cases.tsx 
b/packages/aml-backoffice-ui/src/pages/Cases.tsx
index 8b115ed7e..990c0d2d4 100644
--- a/packages/aml-backoffice-ui/src/pages/Cases.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Cases.tsx
@@ -12,59 +12,6 @@ import { buildQuerySignature } from "../account.js";
 import { handleNotOkResult } from "../utils/errors.js";
 import { useTranslationContext } from "@gnu-taler/web-util/browser";
 
-const response: AmlExchangeBackend.AmlRecords = {
-  records: [
-    {
-      current_state: 0,
-      h_payto: "QWEQWEQWEQWEWQE",
-      rowid: 1,
-      threshold: "USD 100",
-    },
-    {
-      current_state: 1,
-      h_payto: "ASDASDASD",
-      rowid: 1,
-      threshold: "USD 100",
-    },
-    {
-      current_state: 2,
-      h_payto: "ZXCZXCZXCXZC",
-      rowid: 1,
-      threshold: "USD 1000",
-    },
-    {
-      current_state: 0,
-      h_payto: "QWEQWEQWEQWEWQE",
-      rowid: 1,
-      threshold: "USD 100",
-    },
-    {
-      current_state: 1,
-      h_payto: "ASDASDASD",
-      rowid: 1,
-      threshold: "USD 100",
-    },
-    {
-      current_state: 2,
-      h_payto: "ZXCZXCZXCXZC",
-      rowid: 1,
-      threshold: "USD 1000",
-    },
-  ].map((e, idx) => {
-    e.rowid = idx;
-    e.threshold = `${e.threshold}${idx}`;
-    return e;
-  }),
-};
-
-function doFilter(
-  list: typeof response.records,
-  filter: AmlExchangeBackend.AmlState | undefined,
-): typeof response.records {
-  if (filter === undefined) return list;
-  return list.filter((r) => r.current_state === filter);
-}
-
 export function Cases() {
   const officer = useOfficer();
   const { i18n } = useTranslationContext();
diff --git a/packages/aml-backoffice-ui/src/pages/NewFormEntry.tsx 
b/packages/aml-backoffice-ui/src/pages/NewFormEntry.tsx
index bbd04daee..13e78b169 100644
--- a/packages/aml-backoffice-ui/src/pages/NewFormEntry.tsx
+++ b/packages/aml-backoffice-ui/src/pages/NewFormEntry.tsx
@@ -2,8 +2,12 @@ import { VNode, h } from "preact";
 import { allForms } from "./AntiMoneyLaunderingForm.js";
 import { Pages } from "../pages.js";
 import { NiceForm } from "../NiceForm.js";
-import { AbsoluteTime, Amounts } from "@gnu-taler/taler-util";
+import { AbsoluteTime, Amounts, TalerProtocolTimestamp } from 
"@gnu-taler/taler-util";
 import { AmlExchangeBackend } from "../types.js";
+import { useAmlCasesAPI } from "../hooks/useCaseDetails.js";
+import { useOfficer } from "../hooks/useOfficer.js";
+import { HandleAccountNotReady } from "./HandleAccountNotReady.js";
+import { buildDecisionSignature, buildQuerySignature } from "../account.js";
 
 export function NewFormEntry({
   account,
@@ -12,30 +16,58 @@ export function NewFormEntry({
   account?: string;
   type?: string;
 }): VNode {
+  const officer = useOfficer();
+
   if (!account) {
     return <div>no account</div>;
   }
   if (!type) {
     return <SelectForm account={account} />;
   }
+  if (officer.state !== "ready") {
+    return <HandleAccountNotReady officer={officer} />;
+  }
 
   const selectedForm = Number.parseInt(type ?? "0", 10);
   if (Number.isNaN(selectedForm)) {
     return <div>WHAT! {type}</div>;
   }
   const showingFrom = allForms[selectedForm].impl;
+  const formName = allForms[selectedForm].name
   const initial = {
     fullName: "loggedIn_user_fullname",
     when: AbsoluteTime.now(),
     state: AmlExchangeBackend.AmlState.pending,
-    threshold: Amounts.parseOrThrow("USD:10"),
+    threshold: Amounts.parseOrThrow("ARS:1000"),
   };
+  const api = useAmlCasesAPI()
+  
   return (
     <NiceForm
       initial={initial}
       form={showingFrom(initial)}
-      onSubmit={(v) => {
-        alert(JSON.stringify(v));
+      onSubmit={(formValue) => {
+        if (formValue.state === undefined || formValue.threshold === 
undefined) return;
+        
+        const justification = {
+          index: selectedForm,
+          name: formName,
+          value: formValue
+        }
+        const decision: AmlExchangeBackend.AmlDecision = {
+          justification: JSON.stringify(justification),
+          decision_time: TalerProtocolTimestamp.now(),
+          h_payto: account,
+          new_state: formValue.state,
+          new_threshold: Amounts.stringify(formValue.threshold),
+          officer_sig: "",
+          kyc_requirements: undefined
+        }
+        const signature = buildDecisionSignature(officer.account.signingKey, 
decision);
+        decision.officer_sig = signature
+        api.updateDecision(officer.account.accountId, decision);
+
+        // alert(JSON.stringify(formValue));
       }}
     >
       <div class="mt-6 flex items-center justify-end gap-x-6">
diff --git a/packages/aml-backoffice-ui/src/types.ts 
b/packages/aml-backoffice-ui/src/types.ts
index 104d938b3..429b538e7 100644
--- a/packages/aml-backoffice-ui/src/types.ts
+++ b/packages/aml-backoffice-ui/src/types.ts
@@ -59,6 +59,9 @@ export namespace AmlExchangeBackend {
   type PaytoHash = string;
   type Integer = number;
   type Amount = string;
+  // EdDSA signatures are transmitted as 64-bytes base32
+  // binary-encoded objects with just the R and S values (base32_ binary-only).
+  type EddsaSignature = string;
 
   export interface AmlRecords {
     // Array of AML records matching the query.
@@ -85,4 +88,37 @@ export namespace AmlExchangeBackend {
     pending = 1,
     frozen = 2,
   }
+
+  
+  export interface AmlDecision {
+
+    // Human-readable justification for the decision.
+    justification: string;
+  
+    // At what monthly transaction volume should the
+    // decision be automatically reviewed?
+    new_threshold: Amount;
+  
+    // Which payto-address is the decision about?
+    // Identifies a GNU Taler wallet or an affected bank account.
+    h_payto: PaytoHash;
+  
+    // What is the new AML state (e.g. frozen, unfrozen, etc.)
+    // Numerical values are defined in AmlDecisionState.
+    new_state: Integer;
+  
+    // Signature by the AML officer over a
+    // TALER_MasterAmlOfficerStatusPS.
+    // Must have purpose TALER_SIGNATURE_MASTER_AML_KEY.
+    officer_sig: EddsaSignature;
+  
+    // When was the decision made?
+    decision_time: Timestamp;
+  
+    // Optional argument to impose new KYC requirements
+    // that the customer has to satisfy to unblock transactions.
+    kyc_requirements?: string[];
+  }
+  
+
 }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]