gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: reproducing #9154


From: gnunet
Subject: [taler-wallet-core] branch master updated: reproducing #9154
Date: Fri, 01 Nov 2024 18:33:00 +0100

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

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

The following commit(s) were added to refs/heads/master by this push:
     new 7b93f4abc reproducing #9154
7b93f4abc is described below

commit 7b93f4abc1015179071b37c1fb5251a1b9c96312
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Fri Nov 1 14:32:53 2024 -0300

    reproducing #9154
---
 packages/taler-harness/src/harness/environments.ts |   6 +-
 packages/taler-harness/src/index.ts                |  75 ++++-
 .../integrationtests/test-kyc-skip-expiration.ts   |  57 +++-
 .../src/integrationtests/testrunner.ts             |   8 +-
 packages/taler-util/src/http-client/exchange.ts    |  16 +
 packages/taler-util/src/index.node.ts              |   1 +
 packages/taler-util/src/index.ts                   |  13 +-
 packages/taler-util/src/kyc-aml-utils.ts           |  61 ++++
 packages/taler-util/src/types-taler-aml.ts         | 162 ----------
 packages/taler-util/src/types-taler-exchange.ts    |   5 +
 packages/taler-util/src/types-taler-kyc-aml.ts     | 333 +++++++++++++++++++++
 11 files changed, 561 insertions(+), 176 deletions(-)

diff --git a/packages/taler-harness/src/harness/environments.ts 
b/packages/taler-harness/src/harness/environments.ts
index ba4cace40..d52474427 100644
--- a/packages/taler-harness/src/harness/environments.ts
+++ b/packages/taler-harness/src/harness/environments.ts
@@ -24,6 +24,7 @@
  * Imports
  */
 import {
+  AccountProperties,
   AmlDecisionRequest,
   AmlDecisionRequestWithoutSignature,
   AmountString,
@@ -1063,6 +1064,7 @@ export async function postAmlDecision(
     amlPub: string;
     newRules: LegitimizationRuleSet;
     newMeasure?: string | undefined;
+    properties?: AccountProperties;
   },
 ) {
   const { exchangeBaseUrl, paytoHash, amlPriv, amlPub } = req;
@@ -1074,9 +1076,7 @@ export async function postAmlDecision(
     keep_investigating: false,
     new_rules: req.newRules,
     new_measures: req.newMeasure,
-    properties: {
-      foo: "42",
-    },
+    properties: req.properties ?? {},
   };
 
   const sig = signAmlDecision(decodeCrock(amlPriv), sigData);
diff --git a/packages/taler-harness/src/index.ts 
b/packages/taler-harness/src/index.ts
index dc69c3a28..4a95d8c49 100644
--- a/packages/taler-harness/src/index.ts
+++ b/packages/taler-harness/src/index.ts
@@ -64,10 +64,7 @@ import { deepStrictEqual } from "assert";
 import fs from "fs";
 import os from "os";
 import path from "path";
-import {
-  AmlOutcome,
-  codecForAmlProgramInput,
-} from "../../taler-util/src/types-taler-aml.js";
+import { TalerKycAml } from "@gnu-taler/taler-util";
 import { runBench1 } from "./bench1.js";
 import { runBench2 } from "./bench2.js";
 import { runBench3 } from "./bench3.js";
@@ -85,6 +82,7 @@ import {
 } from "./harness/harness.js";
 import { getTestInfo, runTests } from "./integrationtests/testrunner.js";
 import { lintExchangeDeployment } from "./lint.js";
+import { AML_PROGRAM_FROM_ATTRIBUTES_TO_CONTEXT } from 
"integrationtests/test-kyc-skip-expiration.js";
 
 const logger = new Logger("taler-harness:index.ts");
 
@@ -1434,6 +1432,71 @@ export const amlProgramCli = testingCli.subcommand(
   },
 );
 
+const allAmlPrograms: TalerKycAml.AmlProgramDefinition[] = [
+  {
+    name: "no-rules",
+    logic: (_input, _config) => {
+      const outcome: TalerKycAml.AmlOutcome = {
+        new_rules: {
+          expiration_time: TalerProtocolTimestamp.never(),
+          rules: [],
+          custom_measures: {},
+        },
+        events: [],
+      };
+      return outcome;
+    },
+    requiredAttributes: [],
+    requiredContext: [],
+  },
+  AML_PROGRAM_FROM_ATTRIBUTES_TO_CONTEXT,
+];
+
+amlProgramCli
+  .subcommand("run", "run-program")
+  .requiredOption("name", ["-n", "--name"], clk.STRING)
+  .flag("requires", ["-r"])
+  .flag("attributes", ["-a"])
+  .maybeOption("config", ["-c", "--config"], clk.STRING)
+  .action(async (args) => {
+    const found = allAmlPrograms.find((p) => p.name === args.run.name);
+    if (!found) {
+      logger.error(`Program not found: ${args.run.name}`);
+      logger.error(
+        `you can try "${allAmlPrograms.map((p) => p.name).join(",")}"`,
+      );
+      return;
+    }
+    if (args.run.requires) {
+      logger.info("Reporting requirements");
+      console.log(found.requiredContext.join("\n"));
+      return;
+    }
+
+    if (args.run.attributes) {
+      logger.info("reporting attributes");
+      console.log(found.requiredAttributes.join("\n"));
+      return;
+    }
+
+    const buffers = [];
+    // node.js readable streams implement the async iterator protocol
+    for await (const data of process.stdin) {
+      buffers.push(data);
+    }
+
+    const finalBuffer = Buffer.concat(buffers);
+    const inputStr = finalBuffer.toString("utf-8");
+    const inputJson = JSON.parse(inputStr);
+    const progInput = TalerKycAml.codecForAmlProgramInput().decode(inputJson);
+
+    logger.info(`got input: ${j2s(progInput)}`);
+
+    const outcome = found.logic(progInput, args.run.config);
+
+    console.log(j2s(outcome));
+  });
+
 amlProgramCli
   .subcommand("noRules", "no-rules")
   .flag("requires", ["-r"])
@@ -1463,11 +1526,11 @@ amlProgramCli
     const finalBuffer = Buffer.concat(buffers);
     const inputStr = finalBuffer.toString("utf-8");
     const inputJson = JSON.parse(inputStr);
-    const progInput = codecForAmlProgramInput().decode(inputJson);
+    const progInput = TalerKycAml.codecForAmlProgramInput().decode(inputJson);
 
     logger.info(`got input: ${j2s(progInput)}`);
 
-    const outcome: AmlOutcome = {
+    const outcome: TalerKycAml.AmlOutcome = {
       new_rules: {
         expiration_time: TalerProtocolTimestamp.never(),
         rules: [],
diff --git 
a/packages/taler-harness/src/integrationtests/test-kyc-skip-expiration.ts 
b/packages/taler-harness/src/integrationtests/test-kyc-skip-expiration.ts
index 1a26ca877..f0e06b10c 100644
--- a/packages/taler-harness/src/integrationtests/test-kyc-skip-expiration.ts
+++ b/packages/taler-harness/src/integrationtests/test-kyc-skip-expiration.ts
@@ -18,6 +18,7 @@
  * Imports.
  */
 import {
+  AbsoluteTime,
   codecForAny,
   codecForKycProcessClientInformation,
   codecOptional,
@@ -26,6 +27,7 @@ import {
   encodeCrock,
   j2s,
   signAmlQuery,
+  TalerKycAml,
   TalerProtocolTimestamp,
   TransactionIdStr,
   TransactionMajorState,
@@ -40,6 +42,44 @@ import {
 } from "../harness/environments.js";
 import { GlobalTestState, harnessHttpLib, waitMs } from 
"../harness/harness.js";
 
+export const AML_PROGRAM_FROM_ATTRIBUTES_TO_CONTEXT: 
TalerKycAml.AmlProgramDefinition =
+  {
+    name: "from-attr-to-context",
+    logic: (_input, config) => {
+      const now = AbsoluteTime.toProtocolTimestamp(AbsoluteTime.now());
+      const outcome: TalerKycAml.AmlOutcome = {
+        to_investigate: false,
+        // pushing to info into properties for testing purposes
+        properties: {
+          "this comes": "from the program",
+          input: _input as any,
+          config,
+        },
+        events: [],
+        new_rules: {
+          expiration_time: now,
+          new_check: "info-oauth-test-passed",
+          rules: [],
+          successor_measure: "ask_more_info",
+          custom_measures: {
+            ask_more_info: {
+              context: {
+                info: _input?.attributes,
+                // this is the context info that the KYC-SPA will see
+                WAT: "REALLY?",
+              },
+              check_name: "C2",
+              prog_name: "P2",
+            },
+          },
+        },
+      };
+      return outcome;
+    },
+    requiredAttributes: [],
+    requiredContext: [],
+  };
+
 function adjustExchangeConfig(config: Configuration) {
   config.setString("exchange", "enable_kyc", "yes");
 
@@ -66,7 +106,7 @@ function adjustExchangeConfig(config: Configuration) {
   config.setString(
     "AML-PROGRAM-P1",
     "command",
-    "taler-harness aml-program no-rules",
+    "taler-harness aml-program run-program --name from-attr-to-context",
   );
   config.setString("AML-PROGRAM-P1", "enabled", "true");
   config.setString("AML-PROGRAM-P1", "description", "remove all rules");
@@ -86,9 +126,11 @@ function adjustExchangeConfig(config: Configuration) {
   config.setString("KYC-CHECK-C1", "outputs", "full_name birthdate");
   config.setString("KYC-CHECK-C1", "fallback", "M1");
 
-  config.setString("KYC-CHECK-C2", "type", "INFO");
+  config.setString("KYC-CHECK-C2", "type", "FORM");
+  config.setString("KYC-CHECK-C2", "form_name", "dynamicform");
   config.setString("KYC-CHECK-C2", "description", "my check info!");
   config.setString("KYC-CHECK-C2", "description_i18n", "{}");
+  config.setString("KYC-CHECK-C1", "outputs", "what_the_officer_asked");
   config.setString("KYC-CHECK-C2", "fallback", "M2");
 
   config.setString("KYC-CHECK-C3", "type", "INFO");
@@ -180,6 +222,9 @@ export async function runKycSkipExpirationTest(t: 
GlobalTestState) {
       exchangeBaseUrl: exchange.baseUrl,
       paytoHash: kycPaytoHash,
       newMeasure: "M3",
+      properties: {
+        form: { name: "string" },
+      },
       newRules: {
         expiration_time: TalerProtocolTimestamp.now(),
         custom_measures: {},
@@ -231,6 +276,14 @@ export async function runKycSkipExpirationTest(t: 
GlobalTestState) {
 
     console.log(j2s(clientInfo));
 
+    // Finally here we must see the officer defined form
+    t.assertDeepEqual(clientInfo?.requirements[0].context, {
+      // info contains the properties in the aml decision
+      info: { form: { name: "string" } },
+      // this is fixed by the aml program
+      WAT: "REALLY?",
+    });
+
     break;
   }
 }
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts 
b/packages/taler-harness/src/integrationtests/testrunner.ts
index 4818cff17..2ac8e8383 100644
--- a/packages/taler-harness/src/integrationtests/testrunner.ts
+++ b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -14,7 +14,13 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { CancellationToken, Logger, minimatch } from "@gnu-taler/taler-util";
+import {
+  CancellationToken,
+  Logger,
+  minimatch,
+  TalerKycAml,
+  TalerProtocolTimestamp,
+} from "@gnu-taler/taler-util";
 import * as child_process from "child_process";
 import { spawnSync } from "child_process";
 import * as fs from "fs";
diff --git a/packages/taler-util/src/http-client/exchange.ts 
b/packages/taler-util/src/http-client/exchange.ts
index b8dbdf0cf..7526fd8a0 100644
--- a/packages/taler-util/src/http-client/exchange.ts
+++ b/packages/taler-util/src/http-client/exchange.ts
@@ -1,3 +1,19 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022-2024 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
 import {
   HttpRequestLibrary,
   readSuccessResponseJsonOrThrow,
diff --git a/packages/taler-util/src/index.node.ts 
b/packages/taler-util/src/index.node.ts
index ba4c6cf4e..b853c2c6e 100644
--- a/packages/taler-util/src/index.node.ts
+++ b/packages/taler-util/src/index.node.ts
@@ -21,4 +21,5 @@ initNodePrng();
 export * from "./index.js";
 export * from "./talerconfig.js";
 export * from "./globbing/minimatch.js";
+export * from "./kyc-aml-utils.js";
 export { setPrintHttpRequestAsCurl } from "./http-impl.node.js";
diff --git a/packages/taler-util/src/index.ts b/packages/taler-util/src/index.ts
index d72959caf..d640ba41d 100644
--- a/packages/taler-util/src/index.ts
+++ b/packages/taler-util/src/index.ts
@@ -22,7 +22,12 @@ export * from "./http-client/challenger.js";
 export * from "./http-client/exchange.js";
 export * from "./http-client/merchant.js";
 export * from "./http-client/officer-account.js";
-export { CacheEvictor, BasicOrTokenAuth, BasicAuth, TokenAuth } from 
"./http-client/utils.js";
+export {
+  CacheEvictor,
+  BasicOrTokenAuth,
+  BasicAuth,
+  TokenAuth,
+} from "./http-client/utils.js";
 export * from "./http-status-codes.js";
 export * from "./i18n.js";
 export * from "./iban.js";
@@ -56,12 +61,15 @@ export * from "./timer.js";
 export * from "./transaction-test-data.js";
 export * from "./url.js";
 
+// FIXME: remove all this, needs refactor
 export * from "./types-taler-bank-conversion.js";
 export * from "./types-taler-bank-integration.js";
-export * from "./types-taler-common.js";
 export * from "./types-taler-corebank.js";
 export * from "./types-taler-exchange.js";
 export * from "./types-taler-merchant.js";
+// end
+
+export * from "./types-taler-common.js";
 export * from "./types-taler-sync.js";
 export * from "./types-taler-wallet-transactions.js";
 export * from "./types-taler-wallet.js";
@@ -74,6 +82,7 @@ export * as TalerExchangeApi from "./types-taler-exchange.js";
 export * as TalerMerchantApi from "./types-taler-merchant.js";
 export * as TalerRevenueApi from "./types-taler-revenue.js";
 export * as TalerWireGatewayApi from "./types-taler-wire-gateway.js";
+export * as TalerKycAml from "./types-taler-kyc-aml.js";
 
 export * from "./taler-signatures.js";
 
diff --git a/packages/taler-util/src/kyc-aml-utils.ts 
b/packages/taler-util/src/kyc-aml-utils.ts
new file mode 100644
index 000000000..d689d1b34
--- /dev/null
+++ b/packages/taler-util/src/kyc-aml-utils.ts
@@ -0,0 +1,61 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022-2024 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+import { AmlProgramParams, KycConverterParams } from 
"./types-taler-kyc-aml.js";
+
+// 
https://docs.taler.net/taler-kyc-manual.html#implementing-your-own-aml-programs
+
+export function parseKycConverterParams(): KycConverterParams {
+  return process.argv.reduce((prev, arg, idx, list) => {
+    if (idx === 0) {
+      prev.name = arg;
+    }
+    if (arg === "-v") {
+      prev.showVersion = true;
+    } else if (arg === "-V") {
+      prev.debug = true;
+    } else if (arg === "--list-outputs") {
+      prev.showOutputs = true;
+    } else if (arg === "-h") {
+      prev.showHelp = true;
+    } else if (arg === "-c") {
+      prev.config = list[idx + 1];
+    }
+    return prev;
+  }, {} as KycConverterParams);
+}
+
+export function parseAmlProgramParams(): AmlProgramParams {
+  return process.argv.reduce((prev, arg, idx, list) => {
+    if (idx === 0) {
+      prev.name = arg;
+    }
+    if (arg === "-v") {
+      prev.showVersion = true;
+    } else if (arg === "-V") {
+      prev.debug = true;
+    } else if (arg === "-r") {
+      prev.showRequiredContext = true;
+    } else if (arg === "-a") {
+      prev.showRequiredAttributes = true;
+    } else if (arg === "-h") {
+      prev.showHelp = true;
+    } else if (arg === "-c") {
+      prev.config = list[idx + 1];
+    }
+    return prev;
+  }, {} as AmlProgramParams);
+}
diff --git a/packages/taler-util/src/types-taler-aml.ts 
b/packages/taler-util/src/types-taler-aml.ts
deleted file mode 100644
index 5473c7cce..000000000
--- a/packages/taler-util/src/types-taler-aml.ts
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero 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 Affero General Public License 
along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
-
- SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-/**
- * @fileoverview Type and schema definitions and helpers for the Taler AML 
helpers.
- */
-
-/**
- * Imports.
- */
-import {
-  buildCodecForObject,
-  Codec,
-  codecForAny,
-  codecForList,
-} from "./index.js";
-import { TalerProtocolTimestamp } from "./time.js";
-import {
-  AccountProperties,
-  codecForAccountProperties,
-  LegitimizationRuleSet,
-} from "./types-taler-exchange.js";
-
-export interface AmlProgramInput {
-  // JSON object that was provided as
-  // part of the *measure*.  This JSON object is
-  // provided under "context" in the main JSON object
-  // input to the AML program.  This "context" should
-  // satify both the REQUIRES clause of the respective
-  // check and the output of "-r" from the
-  // AML program's command-line option.
-  context?: Record<string, unknown>;
-
-  // JSON object that captures the
-  // output of a ``[kyc-provider-]`` or (HTML) FORM.
-  // In the case of KYC data provided by providers,
-  // the keys in the JSON object will be the attribute
-  // names and the values must be strings representing
-  // the data. In the case of file uploads, the data
-  // MUST be base64-encoded.
-  // In the case of KYC data provided by HTML FORMs, the
-  // keys will match the HTML FORM field names and
-  // the values will use the `KycStructuredFormData`
-  // encoding.
-  attributes: Record<string, unknown>;
-
-  // JSON array with the results of historic
-  // AML desisions about the account.
-  aml_history: AmlHistoryEntry[];
-
-  // JSON array with the results of historic
-  // KYC data about the account.
-  kyc_history: KycHistoryEntry[];
-}
-
-export interface AmlHistoryEntry {
-  // When was the AML decision taken.
-  decision_time: TalerProtocolTimestamp;
-
-  // What was the justification given for the decision.
-  justification: string;
-
-  // Public key of the AML officer taking the decision.
-  decider_pub: string;
-
-  // Properties associated with the account by the decision.
-  properties: Object;
-
-  // New set of legitimization rules that was put in place.
-  new_rules: LegitimizationRuleSet;
-
-  // True if the account was flagged for (further)
-  // investigation.
-  to_investigate: boolean;
-
-  // True if this is the currently active decision.
-  is_active: boolean;
-}
-
-export interface KycHistoryEntry {
-  // Name of the provider
-  // which was used to collect the attributes. NULL if they were
-  // just uploaded via a form by the account owner.
-  provider_name?: string;
-
-  // True if the KYC process completed.
-  finished: boolean;
-
-  // Numeric `error code <error-codes>`, if the
-  // KYC process did not succeed; 0 on success.
-  code: number;
-
-  // Human-readable description of ``code``. Optional.
-  hint?: string;
-
-  // Optional detail given when the KYC process failed.
-  error_message?: string;
-
-  // Identifier of the user at the KYC provider. Optional.
-  provider_user_id?: string;
-
-  // Identifier of the KYC process at the KYC provider. Optional.
-  provider_legitimization_id?: string;
-
-  // The collected KYC data.
-  // NULL if the attribute data could not
-  // be decrypted or was not yet collected.
-  attributes?: Record<string, unknown>;
-
-  // Time when the KYC data was collected
-  collection_time: TalerProtocolTimestamp;
-
-  // Time when the KYC data will expire.
-  expiration_time: TalerProtocolTimestamp;
-}
-
-export interface AmlOutcome {
-  // Should the client's account be investigated
-  // by AML staff?
-  // Defaults to false.
-  to_investigate?: boolean;
-
-  // Free-form properties about the account.
-  // Can be used to store properties such as PEP,
-  // risk category, type of business, hits on
-  // sanctions lists, etc.
-  properties?: AccountProperties;
-
-  // Types of events to add to the KYC events table.
-  // (for statistics).
-  events?: string[];
-
-  // KYC rules to apply.  Note that this
-  // overrides *all* of the default rules
-  // until the ``expiration_time`` and specifies
-  // the successor measure to apply after the
-  // expiration time.
-  new_rules: LegitimizationRuleSet;
-}
-
-export const codecForAmlProgramInput = (): Codec<AmlProgramInput> =>
-  buildCodecForObject<AmlProgramInput>()
-    .property("aml_history", codecForList(codecForAny()))
-    .property("kyc_history", codecForList(codecForAny()))
-    .property("attributes", codecForAccountProperties())
-    .property("context", codecForAny())
-    .build("AmlProgramInput");
diff --git a/packages/taler-util/src/types-taler-exchange.ts 
b/packages/taler-util/src/types-taler-exchange.ts
index ba341d4a9..55c88e29a 100644
--- a/packages/taler-util/src/types-taler-exchange.ts
+++ b/packages/taler-util/src/types-taler-exchange.ts
@@ -1776,6 +1776,10 @@ export interface KycRequirementInformation {
   // English description of the requirement.
   description: string;
 
+  // Object with arbitrary additional context, completely depends on
+  // the specific form.
+  context?: Object;
+
   // Map from IETF BCP 47 language tags to localized
   // description texts.
   description_i18n?: { [lang_tag: string]: string };
@@ -2581,6 +2585,7 @@ export const codecForKycRequirementInformation =
         ),
       )
       .property("description", codecForString())
+      .property("context", codecOptional(codecForAny()))
       .property(
         "description_i18n",
         codecOptional(codecForInternationalizedString()),
diff --git a/packages/taler-util/src/types-taler-kyc-aml.ts 
b/packages/taler-util/src/types-taler-kyc-aml.ts
new file mode 100644
index 000000000..d7be15408
--- /dev/null
+++ b/packages/taler-util/src/types-taler-kyc-aml.ts
@@ -0,0 +1,333 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022-2024 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+import {
+  buildCodecForObject,
+  Codec,
+  codecForAccountProperties,
+  codecForAny,
+  codecForList,
+} from "./index.js";
+import {
+  AmountString,
+  Integer,
+  RelativeTime,
+  Timestamp,
+} from "./types-taler-common.js";
+
+// 
https://docs.taler.net/taler-kyc-manual.html#implementing-your-own-aml-programs
+
+export type AmlProgram = (
+  input: AmlProgramInput | undefined,
+  config: string | undefined,
+) => AmlOutcome;
+
+export type KycConverter = (
+  input: object | undefined,
+  config: string | undefined,
+) => object;
+
+export type AmlProgramParams = {
+  name: string;
+  debug?: boolean;
+  showVersion?: boolean;
+  showRequiredContext?: boolean;
+  showRequiredAttributes?: boolean;
+  showHelp?: boolean;
+  config?: string;
+};
+
+export type KycConverterParams = {
+  name: string;
+  debug?: boolean;
+  showVersion?: boolean;
+  showOutputs?: boolean;
+  showHelp?: boolean;
+  config?: string;
+};
+
+export type KycConverterDefinition = {
+  name: string;
+  logic: KycConverter;
+  outputs: string[];
+};
+
+export type AmlProgramDefinition = {
+  name: string;
+  requiredContext: string[];
+  requiredAttributes: string[];
+  logic: AmlProgram;
+};
+
+export interface AmlProgramInput {
+  // JSON object that was provided as
+  // part of the *measure*.  This JSON object is
+  // provided under "context" in the main JSON object
+  // input to the AML program.  This "context" should
+  // satify both the REQUIRES clause of the respective
+  // check and the output of "-r" from the
+  // AML program's command-line option.
+  context?: any;
+
+  // JSON object that captures the
+  // output of a [kyc-provider-] or (HTML) FORM.
+  // In the case of KYC data provided by providers,
+  // the keys in the JSON object will be the attribute
+  // names and the values must be strings representing
+  // the data. In the case of file uploads, the data
+  // MUST be base64-encoded.
+  // In the case of KYC data provided by HTML FORMs, the
+  // keys will match the HTML FORM field names and
+  // the values will use the KycStructuredFormData
+  // encoding.
+  attributes: any;
+
+  // JSON array with the results of historic
+  // AML desisions about the account.
+  aml_history: AmlHistoryEntry[];
+
+  // JSON array with the results of historic
+  // KYC data about the account.
+  kyc_history: KycHistoryEntry[];
+}
+
+export interface AmlHistoryEntry {
+  // When was the AML decision taken.
+  decision_time: Timestamp;
+
+  // What was the justification given for the decision.
+  justification: string;
+
+  // Public key of the AML officer taking the decision.
+  decider_pub: string;
+
+  // Properties associated with the account by the decision.
+  properties: Object;
+
+  // New set of legitimization rules that was put in place.
+  new_rules: LegitimizationRuleSet;
+
+  // True if the account was flagged for (further)
+  // investigation.
+  to_investigate: boolean;
+
+  // True if this is the currently active decision.
+  is_active: boolean;
+}
+export interface KycHistoryEntry {
+  // Name of the provider
+  // which was used to collect the attributes. NULL if they were
+  // just uploaded via a form by the account owner.
+  provider_name?: string;
+
+  // True if the KYC process completed.
+  finished: boolean;
+
+  // Numeric error code, if the
+  // KYC process did not succeed; 0 on success.
+  code: number;
+
+  // Human-readable description of code. Optional.
+  hint?: string;
+
+  // Optional detail given when the KYC process failed.
+  error_message?: string;
+
+  // Identifier of the user at the KYC provider. Optional.
+  provider_user_id?: string;
+
+  // Identifier of the KYC process at the KYC provider. Optional.
+  provider_legitimization_id?: string;
+
+  // The collected KYC data.
+  // NULL if the attribute data could not
+  // be decrypted or was not yet collected.
+  attributes?: Object;
+
+  // Time when the KYC data was collected
+  collection_time: Timestamp;
+
+  // Time when the KYC data will expire.
+  expiration_time: Timestamp;
+}
+
+export interface AmlOutcome {
+  // Should the client's account be investigated
+  // by AML staff?
+  // Defaults to false.
+  to_investigate?: boolean;
+
+  // Free-form properties about the account.
+  // Can be used to store properties such as PEP,
+  // risk category, type of business, hits on
+  // sanctions lists, etc.
+  properties?: AccountProperties;
+
+  // Types of events to add to the KYC events table.
+  // (for statistics).
+  events?: string[];
+
+  // KYC rules to apply.  Note that this
+  // overrides *all* of the default rules
+  // until the expiration_time and specifies
+  // the successor measure to apply after the
+  // expiration time.
+  new_rules: LegitimizationRuleSet;
+}
+
+// All fields in this object are optional. The actual
+// properties collected depend fully on the discretion
+// of the exchange operator;
+// however, some common fields are standardized
+// and thus described here.
+export interface AccountProperties {
+  // True if this is a politically exposed account.
+  // Rules for classifying accounts as politically
+  // exposed are country-dependent.
+  pep?: boolean;
+
+  // True if this is a sanctioned account.
+  // Rules for classifying accounts as sanctioned
+  // are country-dependent.
+  sanctioned?: boolean;
+
+  // True if this is a high-risk account.
+  // Rules for classifying accounts as at-risk
+  // are exchange operator-dependent.
+  high_risk?: boolean;
+
+  // Business domain of the account owner.
+  // The list of possible business domains is
+  // operator- or country-dependent.
+  business_domain?: string;
+
+  // Is the client's account currently frozen?
+  is_frozen?: boolean;
+
+  // Was the client's account reported to the authorities?
+  was_reported?: boolean;
+
+  [key: string]: string | boolean | number | undefined;
+}
+
+export interface LegitimizationRuleSet {
+  // When does this set of rules expire and
+  // we automatically transition to the successor
+  // measure?
+  expiration_time: Timestamp;
+
+  // Name of the measure to apply when the expiration time is
+  // reached.  If not set, we refer to the default
+  // set of rules (and the default account state).
+  successor_measure?: string;
+
+  // Legitimization rules that are to be applied
+  // to this account.
+  rules: KycRule[];
+
+  // Custom measures that KYC rules and the
+  new_check?: string;
+  // successor_measure may refer to.
+  custom_measures: { [measure: string]: MeasureInformation };
+}
+
+export interface KycRule {
+  // Type of operation to which the rule applies.
+  //
+  // Must be one of "WITHDRAW", "DEPOSIT",
+  // (p2p) "MERGE", (wallet) "BALANCE",
+  // (reserve) "CLOSE", "AGGREGATE",
+  // "TRANSACTION" or "REFUND".
+  operation_type: string;
+
+  // The measures will be taken if the given
+  // threshold is crossed over the given timeframe.
+  threshold: AmountString;
+
+  // Over which duration should the threshold be
+  // computed.  All amounts of the respective
+  // operation_type will be added up for this
+  // duration and the sum compared to the threshold.
+  timeframe: RelativeTime;
+
+  // Array of names of measures to apply.
+  // Names listed can be original measures or
+  // custom measures from the AmlOutcome.
+  // A special measure "verboten" is used if the
+  // threshold may never be crossed.
+  measures: string[];
+
+  // If multiple rules apply to the same account
+  // at the same time, the number with the highest
+  // rule determines which set of measures will
+  // be activated and thus become visible for the
+  // user.
+  display_priority: Integer;
+
+  // True if the rule (specifically, operation_type,
+  // threshold, timeframe) and the general nature of
+  // the measures (verboten or approval required)
+  // should be exposed to the client.
+  // Defaults to "false" if not set.
+  exposed?: boolean;
+
+  // True if all the measures will eventually need to
+  // be satisfied, false if any of the measures should
+  // do.  Primarily used by the SPA to indicate how
+  // the measures apply when showing them to the user;
+  // in the end, AML programs will decide after each
+  // measure what to do next.
+  // Default (if missing) is false.
+  is_and_combinator?: boolean;
+}
+
+export interface MeasureInformation {
+  // Name of a KYC check.
+  check_name: string;
+
+  // Name of an AML program.
+  prog_name: string;
+
+  // Context for the check. Optional.
+  context?: Object;
+
+  // Operation that this measure relates to.
+  // NULL if unknown. Useful as a hint to the
+  // user if there are many (voluntary) measures
+  // and some related to unlocking certain operations.
+  // (and due to zero-amount thresholds, no measure
+  // was actually specifically triggered).
+  //
+  // Must be one of "WITHDRAW", "DEPOSIT",
+  // (p2p) "MERGE", (wallet) "BALANCE",
+  // (reserve) "CLOSE", "AGGREGATE",
+  // "TRANSACTION" or "REFUND".
+  // New in protocol **v21**.
+  operation_type?: string;
+
+  // Can this measure be undertaken voluntarily?
+  // Optional, default is false.
+  // Since protocol **vATTEST**.
+  voluntary?: boolean;
+}
+
+export const codecForAmlProgramInput = (): Codec<AmlProgramInput> =>
+  buildCodecForObject<AmlProgramInput>()
+    .property("aml_history", codecForList(codecForAny()))
+    .property("kyc_history", codecForList(codecForAny()))
+    .property("attributes", codecForAccountProperties())
+    .property("context", codecForAny())
+    .build("AmlProgramInput");

-- 
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]