summaryrefslogtreecommitdiff
path: root/design-documents
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2024-04-14 14:38:22 +0200
committerChristian Grothoff <christian@grothoff.org>2024-04-14 14:38:22 +0200
commitbda831579056f24d776260ae207872fda792a127 (patch)
tree3cee854570f16ad3072b89e64e6b2f21ab03695e /design-documents
parent56d18de9072157a10d190135dc71ab6a202b6e81 (diff)
downloaddocs-bda831579056f24d776260ae207872fda792a127.tar.gz
docs-bda831579056f24d776260ae207872fda792a127.tar.bz2
docs-bda831579056f24d776260ae207872fda792a127.zip
work on KYC DD
Diffstat (limited to 'design-documents')
-rw-r--r--design-documents/023-taler-kyc.rst653
1 files changed, 453 insertions, 200 deletions
diff --git a/design-documents/023-taler-kyc.rst b/design-documents/023-taler-kyc.rst
index 01e3ec7f..f47e98a4 100644
--- a/design-documents/023-taler-kyc.rst
+++ b/design-documents/023-taler-kyc.rst
@@ -4,21 +4,20 @@ DD 23: Taler KYC
Summary
=======
-This document discusses the Know-your-customer (KYC) processes supported by Taler.
+This document discusses the Know-your-customer (KYC) and Anti-Money Laundering
+(AML) processes supported by Taler.
Motivation
==========
-To legally operate, Taler has to comply with KYC regulation that requires
+To legally operate, Taler has to comply with KYC/AML regulation that requires
banks to identify parties involved in transactions at certain points.
Requirements
============
-The solution should support fees to be paid by the user for the KYC process (#7365).
-
Taler needs to take *measures* based on the following primary *triggers*:
* Customer withdraws money over a monthly threshold
@@ -48,8 +47,15 @@ Taler needs to take *measures* based on the following primary *triggers*:
customer records against the list
-For the different *measures*, there are various different possible KYC/AML *checks*
-that could happen:
+Process requirements
+^^^^^^^^^^^^^^^^^^^^
+
+The key consideration here is *plausibilization*: staff needs to
+check that the client-provided information is plausible. As this
+is highly case-dependent, this cannot be automated.
+
+For the different *measures*, there are various different possible KYC/AML
+*checks* that could happen:
* In-person validation by AML staff
* Various forms to be filled by AML staff
@@ -82,9 +88,36 @@ There are also various *outcomes*:
The outcome of a *check* can trigger further *measures* (including
expiration of the outcome state).
+As a result, we largely end up in a large state machine where the AML staff has
+serious flexibiltiy while the user needs guidance as to the possible next moves
+and/or to the current state of their account (where some information must not be
+disclosed).
+
+
+Documentation requirements
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For each account we must:
+
+* define risk-profile (902.4, 905.1)
+* document the specific setup, likely not just the INI file
+* should have some key AMLA file attributes, such as:
+
+ * File opened, file closed (keep data for X years afterwards!)
+ * low-risk or high-risk business relationship
+ * PEP status
+ * business domain
+ * authority notification dates (possibly multiple) with
+ voluntary or mandatory notification classification
Finally, we need to produce statistics:
+* There must be a page with an overview of AMLA files with opening
+ and closing dates and an easy way to determine for any day the
+ number of open AMLA files
+* Technically, we also need a list of at-risk transactions and of
+ frozen transactions, but given that we can really only freeze
+ on an account-basis, I think there is nothing to do here
* number of incidents reported (voluntarily, required)
* number of business relationships at any point in time
* number of risky business relationships (PEP, etc.)
@@ -94,18 +127,24 @@ Finally, we need to produce statistics:
For this high-level monitoring, we need certain designated critical events to
be tracked in the system statistics:
- * account opened
- * set to high risk
- * set to low risk
- * suspicious activity report filed with authority
- * account frozen
- * account unfrozen
- * account closed
+* account opened
+* set to high risk
+* set to low risk
+* suspicious activity report filed with authority
+* account frozen
+* account unfrozen
+* account closed
-As a result, we largely end up in a large state machine where the AML staff has
-serious flexibiltiy while the user needs guidance as to the possible next moves
-and/or to the current state of their account (where some information must not be
-disclosed).
+
+Further considerations
+^^^^^^^^^^^^^^^^^^^^^^
+
+On top of all of this, we need to plan some *diagnostics* to determine when
+components fail (such as scripts or external services providing malformed
+results).
+
+Optionally, in the future, the solution should support fees to be paid by the
+user for *voluntary* KYC processes related to attestation (#7365).
Proposed Solution
@@ -116,43 +155,41 @@ For the different *measures*, we define:
* Who has to do something (AML staff, user, nobody)
* Contextual input data to be provided (with templating, e.g. amount set dynamically based on the *trigger*)
-* A *check* to be performed
+* A *check* to be performed (user-interactive or staff-interactive)
+* Another *measure* to take on failure of a user-interactive check
* A *program* that uses data from the *check* as well as *context* data
to determine an *outcome* which is the specific operational state
(normal, held on staff, held on user, frozen, etc.) the account is to transition to
* What information about the state to show to the user (normal, information required, pending, etc.)
-* For user-interactive checks:
-
- * Web page template with instructions to render (with either a form to fill or links to external checks);
- here the context could provide an array of choices!
- * Possibly an external check to set up (if any); for cost-reasons, we should only do one at a time,
- and probably should then always redirect the browser to that check.
- * A *measure* to take on failure of the external check
+For the user-interactive checks we need a SPA (for KYC) that is given:
-* For (AML) staff-interactive checks:
+* instructions to render (with either a form to fill or links to external checks);
+ here the context could provide an array of choices!
+* possibly an external check that was set up (if any); for cost-reasons, we should only do one at a time,
+ and probably should then always redirect the browser to that check.
- * UI to file forms and upload documentation (without state transition)
- * UI to decide on next measure (providing context); here, the exchange needs
- to expose the list of available *measures* and required *context* for each
+For the staff-interactive checks we need a SPA (for AML):
-* Non-interactive measures (normal operation, account frozen) need:
+* to file forms and upload documentation (without state transition)
+* to decide on next measure (providing context); here, the exchange needs
+ to expose the list of available *measures* and required *context* for each
- * Expiration time (in context)
- * Measure to trigger upon expiration, again with context
- (renew documents, resume normal operation, etc.)
+For non-interactive measures (normal operation, account frozen) we need:
+* Expiration time (in context)
+* Measure to trigger upon expiration, again with context
+ (renew documents, resume normal operation, etc.)
We need some customer-driven interactivity in KYB/KYC process, for example the
user may need to be given choices (address vs. phone, individual vs. business,
order in which to provide KYC data of beneficiaries). As a result, the
-exchange needs to serve some "master" page for measures where the user is
-shown the next step(s) or choices (which person to collect KYC data on,
-whether to run challenger on phone number of physical address, etc.).
-That page should also potentially contain a form to allow the customer to
-directly upload documents to us (like business registration) instead of to
-some KYC provider. This is because KYC providers may not be flexible
-enough.
+exchange needs to serve some SPA for measures where the user is shown the next
+step(s) or choices (which person to collect KYC data on, whether to run
+challenger on phone number of physical address, etc.). The SPA should also
+potentially contain a form to allow the customer to directly upload documents
+to us (like business registration) instead of to some KYC provider. This is
+because KYC providers may not be flexible enough.
Similarly, the AML staff will need to be able to trigger rather complex
KYB/KYC processes, like "need KYC on X and Y and Z" or "phone number or
@@ -161,29 +198,6 @@ should be possible to request not only filled forms, but arbitrary
documents.
-Documentation
-^^^^^^^^^^^^^
-
-* We must define risk-profile (902.4, 905.1)
-* We must document the specific setup, likely not just the INI file
-* We probably should have some key AMLA file attributes, such as:
-
- * File opened, file closed (keep data for X years afterwards!)
- * low-risk or high-risk business relationship
- * PEP status
- * business domain
- * authority notification dates (possibly multiple) with
- voluntary or mandatory notification classification
-
-* There must be a page with an overview of AMLA files with opening
- and closing dates and an easy way to determine for any day the
- number of open AMLA files
-
-* Technically, we also need a list of at-risk transactions and of
- frozen transactions, but given that we can really only freeze
- on an account-basis, I think there is nothing to do here
-
-
Terminology
^^^^^^^^^^^
@@ -195,7 +209,7 @@ Terminology
* **Context**: Context is information provided as input into a *check* and *program* to customize their execution. The context is initially set by the *trigger*, but may evolve as the *account* undergoes *measures*. For each *check* and *program*, the required *context* data must be specified.
-* **Cost**: Metric for the business expense for a KYC check at a certain *provider*. Not in any currency, costs are simply relative and non-negative values. Costs are considered when multiple choices are allowed by the *configuration*.
+* **Cost**: How much would a client have to pay for a KYC process (if they voluntarily choose to do so for attestation).
* **Expiration**: KYC legitimizations may be outdated. Expiration rules determine when *checks* have to be performed again.
@@ -217,28 +231,6 @@ Terminology
New Endpoints
^^^^^^^^^^^^^
-We introduce a new ``wire_targets`` table into the exchange database. This
-table is referenced as the source or destination of payments (regular deposits
-and also P2P payments). A positive side-effect is that we reduce duplication
-in the ``reserves_in``, ``wire_out`` and ``deposits`` tables as they can
-reference this table.
-
-We introduce a new ``legitimization_processes`` table that tracks the status
-of a legitimization process at a provider, including the configuration section
-name, the user/account name at the provider, and some legitimization
-identifier for the process at the provider. In this table, we additionally
-store information related to the KYC status of the underlying payto://-URI, in
-particular when the KYC expires (0 if it was never done).
-
-Finally, we introduce a new ``legitimization_requirements`` table that
-contains a list of checks required for a particular wire target. When KYC is
-triggered (say when some endpoint returns an HTTP status code of 451) a
-new requirement is first put into the requirements table. Then, when the
-client identifies as business or individual the specific legitimization
-process is started. When the taler-exchange-aggregator triggers a KYC check
-the merchant can observe this when a 202 (Accepted) status code is returned
-on GET ``/deposits/`` with the respective legitimization requirement row.
-
The new ``/kyc-check/`` endpoint is based on the legitimization requirements
serial number and receives the business vs. individual status from the client.
Access is ``authenticated`` by also passing the hash of the payto://-URI.
@@ -247,19 +239,45 @@ initiate a KYC process are not very sensitive.) Given this triplet, the
``/kyc-check/`` endpoint returns either the (positive) KYC status or redirects
the client (202) to the next required stage of the KYC process. The
redirection must be for an HTTP(S) endpoint to be triggered via a simple HTTP
-GET. As this endpoint is involved in every KYC check at the beginning, this
-is also the place where we can integrate the payment process for the KYC fee.
-
-The specific KYC provider to be executed depends on the configuration (see
-below) which specifies a ``$PROVIDER_SECTION`` for each authentication procedure.
-For each (enabled) provider, the exchange has a logic plugin which
-(asynchronously) determines the redirect URL for a given wire target. See
-below for a description of the high-level process for different providers.
-
-Upon completion of the process at the KYC provider, the provider must trigger
-a GET request to a new ``/kyc-proof/$H_PAYTO/$PROVIDER_SECTION`` endpoint.
-This may be done either by redirecting the browser of the user to that
-endpoint. Once this endpoint is triggered, the exchange will pass the
+GET. It must always be the same endpoint for the same client, as the
+wallet/merchant backend are not required to check for changes to this
+endpoint.
+
+A new set of ``/kyc-spa/$HASH`` GET endpoints is created per client ``$HASH`` that
+serves the KYC SPA. This is where the ``/kyc-check/`` endpoint will redirect
+clients unless all KYC/AML requirements are satisfied. The KYC SPA will
+use the ``$HASH`` of its URL to initialize itself via the ``/kyc-info/$HASH``
+endpoint family.
+
+A new set of ``/kyc-info/$HASH`` GET endpoints is created per client ``$HASH``
+to return information about the state of the KYC or AML process to the client.
+The SPA uses this information to show the user an appropriate dialog. The SPA
+should also long-poll this endpoint for changes to the AML/KYC state. Note
+that this is a client-facing endpoint, so it will only provide a restricted
+amount of information to the customer (as some laws may forbid us to inform
+particular customers about their true status). The endpoint will typically
+inform the SPA about possible choices to proceed, such as directly uploading
+files, contacting AML staff, or proceeding with a particular KYC process at
+an external provider (such as Challenger). If the user chooses to initate a
+KYC process at an external provider, the SPA must request the respective
+process to be set-up by the exchange via the ``/kyc-start/`` endpoint.
+
+The new ``/kyc-upload/$ID`` POST endpoint allows the SPA to upload
+client-provided evidence. The ``$ID`` will be provided as part of the
+``/kyc-info`` body. This is for checks of type ``FORM``.
+
+The new ``/kyc-start/$ID`` POST endpoint allows the SPA to set up a new
+external KYC process. It will return the (GET) URL that the client must open
+to begin the KYC process. The SPA should probably open this URL in a new
+window or tab. The ``$ID`` will be provided as part of the ``/kyc-info``
+body. As this endpoint is involved in every KYC check at the beginning, this
+is also the place where we could integrate the payment process for the KYC fee
+in the future.
+
+Upon completion of the process at the external KYC provider, the provider must
+trigger a GET request to a new ``/kyc-proof/$H_PAYTO/$PROVIDER_SECTION``
+endpoint. This may be done either by redirecting the browser of the user to
+that endpoint. Once this endpoint is triggered, the exchange will pass the
received arguments to the respective logic plugin. The logic plugin will then
(asynchronously) update the KYC status of the user. The logic plugin should
return a human-readable HTML page with the KYC result to the user.
@@ -274,9 +292,28 @@ endpoint works for GET or POST, again as details depend on the KYC provider.
In contrast to ``kyc-proof``, the response does NOT go to the end-users'
browser and should thus only indicate success or failure.
+The new ``/wallet-kyc`` POST endpoint allows a wallet to notify an exchange
+if it will cross a balance threshold. Here, the ``balance`` specified should
+be the threshold (from the ``wallet_balance_limit_without_kyc`` array) that
+the wallet would cross, and *not* the *exact* balance of the wallet. The
+exchange will respond with a wire target UUID. The wallet can then use this
+UUID to being the KYC process at ``/kyc-check/``. The wallet must only proceed
+to obtain funds exceeding the threshold after the KYC process has
+concluded. While wallets could be "hacked" to bypass this measure (we cannot
+cryptographically enforce this), such modifications are a terms of service
+violation which may have legal consequences for the user.
+
+
+To enable the AML staff SPA to give AML staff a choice of possible measures, a
+new endpoint ``/aml/$OFFICER_PUB/measures`` is added that allows the AML SPA
+to dynamically GET the list of available measures.
+It returns a list of known KYC checks (by name)
+with their descriptions and a list of AML programs
+with information about the required context.
-Legitimization Hooks
-^^^^^^^^^^^^^^^^^^^^
+
+Modifications to existing endpoints
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When withdrawing, the exchange checks if the KYC status is acceptable. If no
KYC was done and if either the amount withdrawn over a particular timeframe
@@ -305,85 +342,276 @@ account-reserve key pair. This should be the same key that is also used to
receive wallet-to-wallet payments. Then, *before* a wallet performs an
operation that would cause it to exceed the balance threshold in terms of
funds held from a particular exchange, it *should* first request the user to
-complete the KYC process.
+complete the KYC process. For that, the wallet should POST to the new
+``/wallet-kyc`` endpoint, providing its long-term reserve-account public key
+and a signature requesting permission to exceed the account limit.
-For that, the wallet should POST to the new ``/wallet-kyc`` endpoint,
-providing its long-term reserve-account public key and a signature requesting
-permission to exceed the account limit. Here, the ``balance`` specified should
-be the threshold (from the ``wallet_balance_limit_without_kyc`` array) that
-the wallet would cross, and *not* the *exact* balance of the wallet. The
-exchange will respond with a wire target UUID. The wallet can then use this
-UUID to being the KYC process at ``/kyc-check/``. The wallet must only proceed
-to obtain funds exceeding the threshold after the KYC process has
-concluded. While wallets could be "hacked" to bypass this measure (we cannot
-cryptographically enforce this), such modifications are a terms of service
-violation which may have legal consequences for the user.
+Configuration of external KYC providers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For each KYC provider that could contribute to checks the configuration
+specifies a ``$PROVIDER_SECTION`` for each authentication procedure. For each
+(enabled) provider, the exchange has a logic plugin which (asynchronously)
+determines the redirect URL for a given wire target. See below for a
+description of the high-level process for different providers.
+
+ .. code-block:: ini
+
+ [kyc-provider-$PROVIDER_ID]
+
+ # Which plugin is responsible for this provider?
+ LOGIC = PLUGIN_NAME
+
+ # Optional cost, useful if clients want to voluntarily
+ # trigger authentication procedures for attestation.
+ COST = EUR:5
+
+ # Plus additional logic-specific options, e.g.:
+ AUTHORIZATION_TOKEN = superdupersecret
+
+ # Other logic-specific internal options (example):
+ FORM_ID = business_legi_form
+
+ # Description of the outputs provided by the check.
+ # Basically, the check's output is expected to
+ # provide the following fields as inputs into
+ # a subsequent AML program.
+ ATTRIBUTES = business_name street city country registration
+
+
+
+Configuration of possible KYC/AML checks
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The configuration specifies a set of possible KYC checks offered by external
+providers, one per configuration section:
+
+ .. code-block:: ini
+
+ [kyc-check-$CHECK_NAME]
+
+ # Which type of check is this? Also determines
+ # the SPA form to show to the user for this check.
+ #
+ # INFO: wait for staff or contact staff out-of band
+ # (only information shown, no SPA action)
+ # FORM: SPA should show an inline (HTML) form
+ # LINK: SPA may start external KYC process or upload
+ #
+ TYPE = INFO|LINK|FORM
+
+ # Optional. Set to YES to allow this check be
+ # done voluntarily by a client (they may then
+ # still have to pay for it). Used to offer the
+ # SPA to display checks even if they are
+ # not required. Default is NO.
+ VOLUNTARY = YES/NO
+
+ # Provider name, if type is LINK
+ PROVIDER_NAME = name
+
+ # Provider name, if type is FORM
+ FORM_NAME = name
+
+ # Descriptions to use in the SPA to display the check.
+ DESCRIPTION = "Upload your passport picture"
+ DESCRIPTION_I18N = "{"en":"Upload scan of your passport"}"
+
+ # ';'-separated list of fields that the CONTEXT must
+ # provided as inputs to this check. For example,
+ # for a FORM of type CHOICE, this might state
+ # ``choices: String[];``. The type after the ":"
+ # is for now purely for documentation and is
+ # not checked. However, it may be shown to AML staff
+ # when they configure measures.
+ REQUIRES = requirement;
+
+ # **original** measure to take if the check fails
+ # (for any reason, e.g. provider or form fail to
+ # satisfy constraints or provider signals user error)
+ # Usually should point to a measure that requests
+ # AML staff to investigate.
+ FALLBACK = MEASURE_NAME
+
+The list of possible FORM names is fixed in the SPA
+for a particular exchange release.
+
+
+Configuration of legitimization requirement triggers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The configuration also specifies a set of legitimization rules including the
+condition and the measure the condition triggers, one condition per
+configuration section:
+
+ .. code-block:: ini
+
+ [kyc-rule-$RULE_NAME]
+
+ # Operation that triggers this legitimization.
+ # Must be one of WITHDRAW, DEPOSIT, P2P-RECEIVE
+ # or WALLET-BALANCE.
+ OPERATION_TYPE = WITHDRAW
+
+ # Required measure to be performed.
+ REQUIRED_MEASURE = SWISSNESS
+
+ # Threshold amount above which the legitimization is
+ # triggered. The total must be exceeded in the given
+ # timeframe. Can be 'forever'.
+ THRESHOLD = AMOUNT
+
+ # Timeframe over which the amount to be compared to
+ # the THRESHOLD is calculated.
+ # Ignored for WALLET-BALANCE.
+ TIMEFRAME = DURATION
+
+ # Enabled (default is NO)
+ ENABLED = NO
+
+
+AML programs
+^^^^^^^^^^^^
+
+AML programs are helper programs that can:
+
+* Generate a list of *required* context field names
+ for the helper (introspection!) using the "--required-context"
+ command-line switch. The output should use the same
+ syntax as the REQUIRES clause of ``[kyc-check-]``
+ configuration sections, except that new lines
+ MUST be used to separate fields instead of ";".
+* Generate a list of *required* attribute names
+ for the helper (introspection!) using the "--required-attributes"
+ command-line switch. The output should use the same
+ list of names as the ATTRIBUTES in the
+ ``[kyc-provider-]`` configuration section
+ (but may also include FORM field names).
+* Process an input JSON object with context and
+ attributes into an *outcome*.
+
+AML programs are listed in the configuration file,
+one program per section:
+
+ .. code-block:: ini
+
+ [aml-program-$PROG_NAME]
+
+ # Program to run.
+ COMMAND = taler-helper-aml-pep
+
+ # Enabled (default is NO)
+ ENABLED = NO
+
+ # **original** measure to take if COMMAND fails
+ # Usually points to a measure that asks AML staff
+ # to contact the systems administrator.
+ FALLBACK = MEASURE_NAME
+
+The JSON input of AML programs consist of two parts:
+
+* "context": 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 "--requires" from the
+ AML program's command-line option.
+* "attributes": JSON object that captures the
+ output of a ``[kyc-provider-]`` or (HTML) FORM.
+ 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.
+
+The outputs of AML programs must be JSON objects which must state:
+* outcome: what to do with the client's account
+* expiration_date: when does the decision expire (zero to take the next measure immediately)
+* next_measure: which measure to trigger upon expiration of the current outcome; this must be either a string with the name of an **original** KYC measure, or a JSON object with the same information that is usually in ``[kyc-measures-]`` configuration sections (with an array of checks, context for each check, and another AML program).
-Configuration Options
-^^^^^^^^^^^^^^^^^^^^^
-
-The configuration specifies a set of providers, one per configuration section:
-
-[kyc-provider-$PROVIDER_ID]
-# Which plugin is responsible for this provider?
-LOGIC = PLUGIN_NAME
-# Which check does this provider provide?
-PROVIDED_CHECK = SMS
-# Plus additional logic-specific options, e.g.:
-AUTHORIZATION_TOKEN = superdupersecret
-FORM_ID = business_legi_form
-# How long is the data from this check considered valid?
-EXPIRATION = DURATION
-
-The configuration also specifies a set of legitimization
-requirements, one per configuration section:
-
-[kyc-legitimization-$RULE_NAME]
-# Operation that triggers this legitimization.
-# Must be one of WITHDRAW, DEPOSIT, P2P-RECEIVE
-# or WALLET-BALANCE.
-OPERATION_TYPE = WITHDRAW
-# Required measure to be performed.
-REQUIRED_MEASURE = SWISSNESS
-# Threshold amount above which the legitimization is
-# triggered. The total must be exceeded in the given
-# timeframe. Can be 'forever'.
-THRESHOLD = AMOUNT
-# Timeframe over which the amount to be compared to
-# the THRESHOLD is calculated.
-# Ignored for WALLET-BALANCE.
-TIMEFRAME = DURATION
-
-
-Finally, the configuration specifies a set of measures,
-one per configuration section:
-
-[aml-measure-$MEASURE_NAME]
-# Program to run on the context and check data to
-# determine the outcome and next measure.
-PROGRAM = /bin/true
-# Check to run as part of this measure. Optional.
-CHECK = CHECK_NAME
-# Form to show to the user as part of this measure.
-FORM = FORM_NAME
-
-For each FORM_NAME, there then must be
-
-* A HTML template (Mustach) that is instantiated with the
- JSON form context to produce a page to be shown to the user
-* A helper program (named after the form) that can:
-
- * Generate a list of required context attributes
- for the helper (!)
- * Validate and convert an input JSON with context
- attributes into the JSON form context
-
-
-Exchange Database Schema
+If the AML program fails (exits with a failure code or
+does not provide well-formed JSON output) the AML/KYC
+process continues with the FALLBACK measure. This should
+usually be one that asks AML staff to contact the
+systems administrator.
+
+
+Configuration of measures
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Finally, the configuration specifies a set of
+**original** *measures* one per configuration section:
+
+ .. code-block:: ini
+
+ [kyc-measure-$MEASURE_NAME]
+
+ # List of checks that could be run as part of
+ # this measure. The SPA should display *all*
+ # of these checks to the user, as they are given
+ # the choice.
+ # Each check is enabled by providing the
+ # context for the CHECK. The context can be
+ # just an empty JSON object if there is none.
+ CONTEXT_[$CHECK_NAME] = JSON
+
+ # Program to run on the context and check data to
+ # determine the outcome and next measure.
+ PROGRAM = taler-aml-program
+
+.. note::
+
+ The list of *measures* is not complete: AML staff may freely define new
+measures dynamically, usually by selecting checks, an AML program, and
+providing context.
+
+
+Sanity checking
+^^^^^^^^^^^^^^^
+
+On start-up, ``taler-exchange-httpd`` should sanity-check its
+configuration. Specifically, it should validate that for all AML programs the
+input requirements (attributes and context) are claimed to be satisfied by the
+respective checks that may trigger those programs, and similarly that for all
+checks the original measures satisfy the context requirements for their KYC
+checks.
+
+As a result, any component (AML program, form or external check) is warranted
+to be always called with the declared required inputs. Furthermore, we can
+detect if a component fails to produce the required output and the
+configuration contains (presumably safe) FALLBACKs to address this case. The
+exchange *MUST* detect circular failures, like when a FALLBACK triggers a
+measure that itself immediately triggers again the same FALLBACK.
+
+
+Exchange database schema
^^^^^^^^^^^^^^^^^^^^^^^^
+We introduce a new ``wire_targets`` table into the exchange database. This
+table is referenced as the source or destination of payments (regular deposits
+and also P2P payments). A positive side-effect is that we reduce duplication
+in the ``reserves_in``, ``wire_out`` and ``deposits`` tables as they can
+reference this table.
+
+We introduce a new ``legitimization_processes`` table that tracks the status
+of a legitimization process at a provider, including the configuration section
+name, the user/account name at the provider, and some legitimization
+identifier for the process at the provider. In this table, we additionally
+store information related to the KYC status of the underlying payto://-URI, in
+particular when the KYC expires (0 if it was never done).
+
+Finally, we introduce a new ``legitimization_requirements`` table that
+contains a list of checks required for a particular wire target. When KYC is
+triggered (say when some endpoint returns an HTTP status code of 451) a
+new requirement is first put into the requirements table. Then, when the
+client identifies as business or individual the specific legitimization
+process is started. When the taler-exchange-aggregator triggers a KYC check
+the merchant can observe this when a 202 (Accepted) status code is returned
+on GET ``/deposits/`` with the respective legitimization requirement row.
+
+
.. sourcecode:: sql
CREATE TABLE IF NOT EXISTS wire_targets
@@ -429,22 +657,52 @@ Exchange Database Schema
IS 'Identifier for the specific legitimization process at the provider. NULL if legitimization was not started.';
+KYC forms
+^^^^^^^^^
+
+The KYC SPA run by clients needs to support three TYPEs of checks. INFO is
+only about displaying the provided information, LINK is about setting up an
+exteral KYC check and redirecting there. FORM is about displaying a particular
+(HTML) form to the user and POSTing the entered information directly with the
+exchange. Here we describe the forms that must be supported:
+
+* CHOICE: Asks the client a multiple-choice question.
+ The context must include "choices: String[]" with
+ a list of choices to show. Used, for example, to
+ ask a client if they are an individual or a business.
+ The resulting HTML FORM field name must be
+ "choice" and it must be mapped to strings from the
+ choices list.
+* UPLOAD: Asks the client to upload a single file.
+ The context may include "extensions: String[]" with
+ a list of allowed file extensions the client's file
+ must end with (e.g. "png", "pdf", "gif"). In the
+ absence of this context, any file may be uploaded.
+ The context may also include "size_limit: Integer" with
+ the maximum file size in bytes that can be uploaded.
+ The resulting HTML FORM must have two fields,
+ "filename" and "filedata". "filename" must be
+ set to the basename of the original file (to the
+ extend that it is available), and "filedata"
+ to the base64-encoding of the uploaded data.
+
+As with other SPA checks, the KYC form should also show
+the description of the check.
+
+
Merchant modifications
^^^^^^^^^^^^^^^^^^^^^^
A new setting is required where the merchant backend
can be configured for a business (default) or individual.
-.. note::
-
- This still needs to be done!
-
-We introduce new ``kyc_status``, ``kyc_timestamp`` and ``kyc_serial`` fields
-into a new table with primary keys ``exchange_url`` and ``account``. This
-status is updated whenever a deposit is created or tracked, or whenever the
-mechant backend receives a ``/kyc-check/`` response from the exchange. Initially,
-``kyc_serial`` is zero, indicating that the merchant has not yet made any
-deposits and thus does not have an account at the exchange.
+We introduce new ``kyc_ok``, ``aml_decision``, ``kyc_timestamp`` and
+``exchange_kyc_serial`` fields into a new table ``merchant_kyc`` with primary
+keys ``exchange_url`` and ``account_serial``. This status is updated whenever
+a deposit is created or tracked, or whenever the mechant backend receives a
+``/kyc-check/`` response from the exchange. Initially,
+``exchange_kyc_serial`` is zero, indicating that the merchant has not yet made
+any deposits and thus does not have an account at the exchange.
A new private endpoint ``/kyc`` is introduced which allows frontends to
request the ``/kyc`` status of any configured account (including with long
@@ -455,18 +713,18 @@ either that the KYC is OK, or information (same as from the exchange endpoint)
to begin the KYC process.
The merchant backend uses the new field to remember that a KYC is pending
-(after ``/deposit``, or tracing deposits) and the SPA then shows a
+(after detection in ``taler-merchant-depositcheck``) and the SPA then shows a
notification whenever the staff is logged in to the system. The notification
can be hidden for the current day (remembered in local storage).
-The notification links to a (new) KYC status page. When opened, the KYC status
-page first re-checks the KYC status with the exchange. If the KYC is still
-unfinished, that page contains another link to begin the KYC process
-(redirecting to the OAuth 2.0 login page of the legitimization resource
-server), otherwise it shows that the KYC process is done. If the KYC is
-unfinished, the SPA should use long-polling on the KYC status on this page to
-ensure it is always up-to-date, and change to ``KYC satisfied`` should the
-long-poller return with positive news.
+The notification links to a (new) KYC status page. When opened, the KYC SPA
+first re-checks the KYC status with the exchange. If the KYC is still
+unfinished, that SPA will show forms, links or contact information to begin
+the KYC process (for example, redirecting to the OAuth 2.0 login page of the
+legitimization resource server), otherwise it shows that the KYC process is
+done. If the KYC is unfinished, the merchant SPA should use long-polling on
+the KYC status on this page to ensure it is always up-to-date, and change to
+``KYC satisfied`` should the long-poller return with positive news.
..note::
@@ -474,10 +732,6 @@ long-poller return with positive news.
128-bit salt values (to keep ``deposits`` table small) and checks for salt
to be well-formed should be added "everywhere".
-An additional complication will arise once the exchange can trigger a KYC
-fee (402) on ``/kyc-check/``. In this case, the merchant SPA must show the QR
-code to the merchant to allow the merchant to pay the KYC fee with a wallet.
-
Bank requirements
@@ -496,8 +750,8 @@ not on the name of the logic plugin (that we call ``$LOGIC``). Using the
configuration section, the exchange then determines the logic plugin to use.
This section describes the general API for all of the supported KYC providers,
-as well as some details of how this general API could be implemented by the logic for
-different APIs.
+as well as some details of how this general API could be implemented by the
+logic for different APIs.
General KYC Logic Plugin API
@@ -509,7 +763,6 @@ This section provides a sketch of the proposed API for the KYC logic plugins.
- inputs:
+ provider_section (for additional configuration)
- + individual or business user
+ h_payto
- outputs:
+ success/provider-failure