From 2fd678a6bf5841e6461d2819c0bac4d46d8a856a Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 14 Apr 2024 20:47:53 +0200 Subject: kyc spec work --- design-documents/023-taler-kyc.rst | 694 +++++++++++++++++++++++++++++-------- 1 file changed, 559 insertions(+), 135 deletions(-) (limited to 'design-documents/023-taler-kyc.rst') diff --git a/design-documents/023-taler-kyc.rst b/design-documents/023-taler-kyc.rst index 85478d8e..1eb0669e 100644 --- a/design-documents/023-taler-kyc.rst +++ b/design-documents/023-taler-kyc.rst @@ -84,9 +84,14 @@ There are also various *outcomes*: * held, AML staff reviewing evidence for plausibilization (new measure) * automatically frozen until certain day (due to sanctions) * institutionally frozen until certain day (due to order by state authority) +* operation is categorically not allowed (at least above certain limits) -The outcome of a *check* can trigger further *measures* (including -expiration of the outcome state). +Outcomes may also be (partially) public, that is exposed to the client. For +example, we may want to tell a wallet that it has hit a hard withdraw limit, +but might succeed at withdrawing a smaller amount. + +The outcome of a *check* can set new rules or trigger another *measure* (the +latter is conditional on reaching the expiration time of the outcome). 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 @@ -219,11 +224,11 @@ Terminology * **Measure**: Describes the possible outgoing edges from one state in the state machine (including how to show the current state). Each edge is given some *context* and a *check* to be performed as well as a *program* to decide the *outcome* and the next *measure*. -* **Outcome**: Describes the account state that an account ends up in due to the result of a *check*. Outcomes can be that an account is frozen (no transactions possible until freeze expires), held (no transactions possible until another *measure* has been taken), or operating normally. +* **Outcome**: Describes the account state that an account ends up in due to the result of a *check*. Outcomes can be that an account is frozen (no transactions possible until freeze expires), held (no transactions possible until another *measure* has been taken), or operating normally. Outcomes also include a new set of *legitimization rules* to apply and an expiration time at which point a new *measure* will be automatically taken. Finally, parts of the outcome may be explained to the client (for example, to allow a wallet to stay below hard withdraw thresholds). * **Provider**: A provider performs a specific set of *checks* at a certain *cost*. Interaction with a provider is performed by provider-specific *logic*. -* **Program**: An AML helper *program* is given *context* about the current state of an account and the data from a *check* to compute the *outcome*. For example, a *program* may look at the "PEP" field of a KYC check and decide if the outcome is to put the account into ``normal`` or ``held-for-manual-review`` state. A *program* operating on an AML form filed by AML staff will likely be trivial and directly apply the explicit decision taken by the staff member. +* **Program**: An AML helper *program* is given *context* about the current state of an account and the attribute data from a *check* to compute the *outcome*. For example, a *program* may look at the "PEP" field of a KYC check and decide if the outcome is to put the account into ``normal`` or ``held-for-manual-review`` state. * **Type of operation**: The operation type determines which Taler-specific operation has triggered the KYC requirement. We support four types of operation: withdraw (by customer), deposit (by merchant), P2P receive (by wallet) and (high) wallet balance. @@ -231,7 +236,7 @@ Terminology New Endpoints ^^^^^^^^^^^^^ -The new ``/kyc-check/`` endpoint is based on the legitimization requirements +The ``/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. (Weak authentication is acceptable, as the KYC status or the ability to @@ -243,73 +248,332 @@ 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. - -Alternatively, the KYC confirmation may be triggered by a ``/kyc-webhook`` -request. As KYC providers do not necessarily support passing detailed -information in the URL arguments, the ``/kyc-webhook`` only needs to specify -either the ``PROVIDER_SECTION`` *or* the ``LOGIC`` (the name of the plugin -implementing the KYC API). The API-specific webhook logic must then figure -out what exactly the webhook is about on its own. The ``/kyc-webhook/`` -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. +FIXME: update /kyc-check/ endpoint to expose *public* outcomes of previous +checks (such as hard withdrawal limits)! + +.. http:get:: /kyc-spa/{$HASH,$FILENAME} + + A 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. The KYC SPA may download additional + resources via ``/kyc-spa/$FILENAME``. The filenames must not match + base32-encoded SHA-512 hashes. + +.. http:get:: /kyc-info/$HASH + + 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 KYC SPA. 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. + + **Request**: + + *If-None-Match*: The client MAY provide an ``If-None-Match`` header with + an ETag. + + :query timeout_ms=MILLISECONDS: *Optional.* If specified, the exchange will wait up to MILLISECONDS for a change to a more recent legitimization measure before returning a 304 Not Modified. + + **Response**: + + :http:statuscode:`200 OK`: + The body is a `KycProcessClientInformation`. + + *Etag*: Will be set to the serial ID of the measure. Used for long-polling. + + .. ts:def:: KycProcessClientInformation + + interface KycProcessClientInformation { + + // List of requirements. + requirements?: { name : KycRequirementInformation}; + + // True if the client is expected to eventually satisfy all requirements. + // Default (if missing) is false. + is_and_combinator?: boolean + + // List of available voluntary checks the client could pay for. + // Since **vATTEST**. + voluntary_checks?: { name : KycCheckInformation}; + } + + .. ts:def:: KycRequirementInformation + + interface KycRequirementInformation { + + // Which form should be used? Common values include "INFO" + // (to just show the descriptions but allow no action), + // "LINK" (to enable the user to obtain a link via + // ``/kyc-start/``) or any build-in form name supported + // by the SPA. + form: string; + + // English description of the requirement. + description: string; + + // Map from IETF BCP 47 language tags to localized + // description texts. + description_i18n ?: { [lang_tag: string]: string }; + + // ID of the requirement, useful to construct the + // ``/kyc-upload/$ID`` or ``/kyc-start/$ID`` endpoint URLs. + // Present if and only if "form" is not "INFO". + id?: string; + + } + + .. ts:def:: KycCheckInformation + + // Since **vATTEST**. + interface KycCheckInformation { + + // How much would this check cost the client? + cost: Amount; + + // English description of the check. + description: string; + + // Map from IETF BCP 47 language tags to localized + // description texts. + description_i18n ?: { [lang_tag: string]: string }; + + } + + :http:statuscode:`204 No Content`: + There are no open KYC requirements or possible voluntary checks + the client might perform. + + :http:statuscode:`304 Not Modified`: + The KYC requirements did not change. + +.. http:post:: /kyc-upload/$ID + + The ``/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``. + + **Request**: + + Basically oriented along the possible formats of a HTTP form being + POSTed. Details will depend on the form. The server will try to + decode the uploaded body from whatever format it is provided in. + + **Response**: + + :http:statuscode:`204 No Content`: + The information was successfully uploaded. The SPA should fetch + an updated ``/kyc-info/``. + :http:statuscode:`404 Not Found`: + The ``$ID`` is unknown to the exchange. + :http:statuscode:`409 Conflict`: + The upload conflicts with a previous upload. + :http:statuscode:`413 Content Too Large`: + The body is too large. + +.. http:post:: /kyc-start/$ID + + The ``/kyc-start/$ID`` POST endpoint allows the SPA to set up a new + external KYC process. It will return the URL that the client must GET + 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. + + **Request**: + + Use empty JSON body for now. + + **Response**: + + :http:statuscode:`200 Ok`: + The KYC process was successfully initiated. The URL is in a + `KycProcessStartInformation` object. + + .. ts:def:: KycProcessStartInformation + + interface KycProcessStartInformation { + + // URL to open. + redirect_url: string; + } + + :http:statuscode:`404 Not Found`: + The ``$ID`` is unknown to the exchange. + + .. note:: + + 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 (since **vATTEST**). + + +.. http:get:: /kyc-proof/$H_PAYTO/$PROVIDER_SECTION + + 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. + +.. http:get:: /kyc-webhook/*`` +.. http:post:: /kyc-webhook/*`` + + Alternatively, the KYC confirmation may be triggered by a ``/kyc-webhook`` + request. As KYC providers do not necessarily support passing detailed + information in the URL arguments, the ``/kyc-webhook`` only needs to specify + either the ``PROVIDER_SECTION`` *or* the ``LOGIC`` (the name of the plugin + implementing the KYC API). The API-specific webhook logic must then figure + out what exactly the webhook is about on its own. The ``/kyc-webhook/`` + 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. + +.. http:post:: /wallet-kyc`` + + The ``/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. + +.. http:get:: /aml/$OFFICER_PUB/measures + + 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. + + **Request**: + + FIXME: see other AML GET requests? + + **Response**: + + :http:statuscode:`200 Ok`: + Information about possible measures is returned in a + `AvailableMeasureSummary` object. + + .. ts:def:: AvailableMeasureSummary + + interface AvailableMeasureSummary { + + // Available original measures that can be + // triggered directly by default rules. + roots: { "$measure_name" : MeasureInformation }; + + // Available AML programs. + programs: { "$prog_name" : AmlProgramRequirement }; + + // Available KYC checks. + checks: { "$check_name" : KycCheckInformation }; + + } + + .. ts:def:: MeasureInformation + + interface MeasureInformation { + + // Name of a KYC check. + check_name: string; + + // Name of an AML program. + prog_name: string; + + // Context for the check. Could be empty. + context: Object; + + } + + .. ts:def:: AmlProgramRequirement + + interface AmlProgramRequirement { + + // Description of what the AML program does. + description: string; + + // List of required field names in the context + // to run this AML program. + // SPA must check that the AML staff is providing + // adequate CONTEXT when defining a measure using + // this AML program. + context: string[]; + + // List of required attribute names in the + // input of this AML program. These attributes + // are the minimum that the check must produce + // (it may produce more). + inputs: string[]; + + } + + .. ts:def:: KycCheckInformation + + interface KycCheckInformation { + + // Description of the KYC check. Should be shown + // to the AML staff but will also be shown to the + // client when they initiate the check in the KYC SPA. + description: string; + description_i18n: {}; + + // Names of the fields that the CONTEXT must provide + // as inputs to this check. + // SPA must check that the AML staff is providing + // adequate CONTEXT when defining a measure using + // this check. + requires: string[]; + + // Names of the attributes the check will output. + // SPA must check that the outputs match the + // required inputs when combining a KYC check + // with an AML program into a measure. + outputs: string[]; + + // Name of a root measure taken when this check fails. + fallback: string; + } + +.. http:get:: /aml/kyc-statistics/$NAME + + Returns the number of KYC events matching the given + event type ``$NAME`` in the specified time range. + Note that this query can be slow as the statistics + are computed on-demand. (This is OK as such requests + should be rare.) + + **Request**: + + FIXME: add authorization checks, as with other /aml/ requests. + + :query start_date=TIMESTAMP: *Optional*. Specifies the date when to start looking (inclusive). If not given, the start time of the exchange operation is used. + :query end_date=TIMESTAMP: *Optional*. Specifies the date when to stop looking (exclusive). If not given, the current date is used. + + **Response**: + + .. ts:def:: EventCounter + + interface EventCounter { + // Number of events of the specified type in + // the given range. + cnt: Integer; + } Modifications to existing endpoints @@ -365,6 +629,7 @@ description of the high-level process for different providers. # Optional cost, useful if clients want to voluntarily # trigger authentication procedures for attestation. + # Since **vATTEST**. COST = EUR:5 # Plus additional logic-specific options, e.g.: @@ -373,12 +638,17 @@ description of the high-level process for different providers. # 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 - + # Name of a program to run on the output of the plugin + # to convert the result into the desired set of attributes. + # The converter must create a log for the system administrator + # if the provided inputs do not match expectations. + # Note that the converter will be expected to output the + # set of attributes listed under the respective ``[kyc-check-*]`` + # sections. Calling the converter with ``--list-outputs`` + # should generate a (newline-separated) list of attributes + # the converter promises to generate in its JSON output + # (when run regularly). + CONVERTER = taler-exchange-helper-$NAME Configuration of possible KYC/AML checks @@ -406,12 +676,20 @@ providers, one per configuration section: # still have to pay for it). Used to offer the # SPA to display checks even if they are # not required. Default is NO. + # Since **vATTEST**. VOLUNTARY = YES/NO - # Provider name, if type is LINK - PROVIDER_NAME = name + # Provider id, present only if type is LINK. + PROVIDER_ID = id - # Provider name, if type is FORM + # Name of the SPA form, if type is FORM + # "INFO" and "LINK" are reserved and must not be used. + # The exchange server and the SPA must agree on a list + # of supported forms and the resulting attributes. + # + # The SPA should include a JSON resource file + # "forms.json" mapping form names to arrays of + # attribute names each form provides. FORM_NAME = name # Descriptions to use in the SPA to display the check. @@ -427,6 +705,12 @@ providers, one per configuration section: # when they configure measures. REQUIRES = requirement; + # 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. + OUTPUTS = business_name street city country registration + # **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) @@ -463,17 +747,26 @@ configuration section: # display *all* of these measures to the user. # (they have a choice of either which ones, or in # which order they are to be performed). + # A special measure "verboten" is used if the + # threshold may never be crossed. NEXT_MEASURES = SWISSNESS KYB # Context for each of the above measures, optional. MEASURE_CONTEXT_$NAME = CONTEXT - # AND if all REQUIRED_MEASURES will eventually need - # to be satisfied, OR if the user has a choice between + # "yes" if all REQUIRED_MEASURES will eventually need + # to be satisfied, "no" if the user has a choice between # them. Not actually enforced by the exchange, but # primarily used to inform the user whether this is - # an "and" or "or". - COMBINATOR = AND|OR + # an "and" or "or". YES for "and". + AND_COMBINATOR = YES + + # YES if the rule (specifically, operation type, + # threshold, timeframe) and the general nature of + # the next measure (verboten or approval required) + # should be exposed to the client. + # Defaults to NO if not set. + EXPOSED = YES # Threshold amount above which the legitimization is # triggered. The total must be exceeded in the given @@ -506,13 +799,136 @@ AML programs are helper programs that can: 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*. This is the - default behavior if no command-line switches +* Process an input JSON object of type + `AmlProgramInput` into a JSON object of + type `AmlProgramOutcome`. + This is the default behavior if no command-line switches are provided. -AML programs are listed in the configuration file, -one program per section: +.. ts:def:: AmlProgramInput + + 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 "--requires" from the + // AML program's command-line option. + context?: Object; + + // 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. + attributes: Object; + + // JSON array with the results of historic + // AML desisions about the account. + // FIXME: review AmlDecisionDetail spec! + // (need to enable new outcomes!) + aml_history: AmlDecisionDetail[]; + + // JSON array with the results of historic + // KYC data about the account. + // FIXME: review KycDetail spec! + // (need to include AmlProgramOutcome!) + kyc_history: KycDetail[]; + + } + +.. ts:def:: AmlProgramOutcome + + interface AmlProgramOutcome { + + // Should the client's account be investigated + // by AML staff? + // Defaults to false. + to_investigate?: boolean; + + // Should the client's account be frozen? + // Defaults to false. + is_frozen?: boolean; + + // Was the client's account reported to the authorities? + // Defaults to false. + is_reported?: 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?: Object; + + // Types of events to add to the KYC events table. + // (for statistics). + events?: string[]; + + // When does the outcome expire? + expiration: Timestamp; + + // Name of the measure to apply the outcome expires. + // If not set, we revert to the default set + // of rules (and the default account state). + successor_measure: string; + + // Array of KYC rules to apply. Note that this + // array overrides *all* of the default rules. + // Thus, if the array does not have an entry for + // a particular operation, there would be + // no thresholds for that operation! + rules: KycRule[]; + + // Custom measures that KYC rules may refer to. + custom_measures: { "name" : MeasureInformation }; + + } + +.. ts:def:: KycRule + + interface KycRule { + + // Type of operation to which the rule applies. + operation_type: String; + + // Measure to be taken if the given + // threshold is crossed over the given timeframe. + threshold: Amount; + + // Over which duration should the threshold be + // computed. + timeframe: RelativeTime; + + // Array of names of measures to apply. + // Names listed can be original measures or + // custom measures from the `AmlProgramOutcome`. + // A special measure "verboten" is used if the + // threshold may never be crossed. + measures: String[]; + + // 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. + and_combinator: boolean; + } + +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. + +AML programs are listed in the configuration file, one program per section: .. code-block:: ini @@ -521,8 +937,15 @@ one program per section: # Program to run. COMMAND = taler-helper-aml-pep - # Enabled (default is NO) - ENABLED = NO + # Human-readable description of what this + # AML helper program will do. Used to show + # to the AML staff. + DESCRIPTION = "check if the customer is a PEP" + + # True if this AML program is enabled (and thus can be + # used in measures and exposed to AML staff). + # Optional, default is NO. + ENABLED = YES # **original** measure to take if COMMAND fails # Usually points to a measure that asks AML staff @@ -531,37 +954,6 @@ one program per section: # failure. FALLBACK = MEASURE_NAME -The JSON input of an AML program consists of three 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. -* "history": JSON array with the results of historic - data collected about the user. - -The output of an 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) -* combinator: "AND" if all of the 'next_measures' will eventually need to be satisfied, "OR" if those are choices and the user only has to satisfy one of them. -* next_measures: measures to trigger upon expiration of the current outcome; array entries must be either a string with the name of an **original** context-free measure, or JSON objects with the same information that is usually in ``[kyc-measures-]`` configuration sections (with a check name, context, and AML program name). - -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 ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -578,8 +970,7 @@ Finally, the configuration specifies a set of # (on an empty set of attributes). CHECK_NAME = IB_FORM - # Context for the check. - # The context can be + # Context for the check. The context can be # just an empty JSON object if there is none. CONTEXT = {"choices":["individual","business"]} @@ -587,16 +978,15 @@ Finally, the configuration specifies a set of # determine the outcome and next measure. PROGRAM = taler-aml-program -If no ``CHECK_NAME`` is provided at all, the -AML ``PROGRAM`` is to be run immediately. This is -useful if no client-interaction is required to -arrive at a decision. +If no ``CHECK_NAME`` is provided at all, the AML ``PROGRAM`` is to be run +immediately. This is useful if no client-interaction is required to arrive at +a decision. .. 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. + 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 @@ -717,7 +1107,7 @@ on GET ``/deposits/`` with the respective legitimization requirement row. COMMENT ON COLUMN legitimization_outcomes.is_active IS 'TRUE if this is the current authoritative legitimization outcome'; COMMENT ON COLUMN legitimization_outcomes.new_rules - IS 'JSON-encoding of KYC-rules to apply to the various operation types for this account; KYC check should first check if active new rules for a given account exist (and apply specified measures); if not, it should check the default rules to decide if a measure is required'; + IS 'JSON array of KycRule objects to apply to the various operation types for this account; all KYC checks should first check if active new rules for a given account exist in this table (and apply specified measures); if not, it should check the default rules to decide if a measure is required'; CREATE INDEX legitimization_outcomes_active ON legitimization_outcomes(h_payto) @@ -858,8 +1248,8 @@ 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. +A new setting is required where the merchant backend can be configured for a +business (default) or individual. We introduce new ``kyc_ok``, ``aml_decision``, ``kyc_timestamp`` and ``exchange_kyc_serial`` fields into a new table ``merchant_kyc`` with primary @@ -1056,6 +1446,40 @@ For ``/kyc-webhook/``: to tell us anything for sure. The result is then returned. +Types of KYC events +^^^^^^^^^^^^^^^^^^^ + +The ``/aml/kyc-statistics`` endpoint exposes statistics +for various KYC event types. + +We will initially support the use of the following types +of KYC events in the SPA (and have a dialog to show the +total number of any of these for any specified time range): + +* account-open +* account-closed +* voluntary-sar +* mandatory-sar +* pep-started +* pep-ended +* risky-started +* risky-ended +* account-frozen +* account-unfrozen + +Based on these, the SPA should also be albe to show active +statistics (for any given timestamp) on the total number of: + +* open accounts +* frozen accounts +* high-risk accounts +* PEPs served + +.. note:: + + This can be done by simply running the queries with + a start time of zero and subtracting. + Alternatives ============ -- cgit v1.2.3