summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api-bank-conversion-info.rst4
-rw-r--r--core/api-bank-wire.rst24
-rw-r--r--core/api-common.rst55
-rw-r--r--core/api-corebank.rst74
-rw-r--r--core/api-exchange.rst848
-rw-r--r--core/api-merchant.rst59
-rw-r--r--core/api-terminal.rst27
-rw-r--r--design-documents/023-taler-kyc.rst632
-rw-r--r--frags/installing-ubuntu.rst6
-rw-r--r--libeufin/index.rst1
-rw-r--r--libeufin/regional-automated-manual.rst1
-rw-r--r--libeufin/regional-custom-manual.rst1
-rw-r--r--libeufin/regional-manual-use.rst (renamed from frags/regional-manual-use.rst)19
-rw-r--r--manpages/libeufin-nexus.1.rst22
-rw-r--r--manpages/libeufin-nexus.conf.5.rst58
-rw-r--r--manpages/taler.conf.5.rst189
-rw-r--r--orphaned/python-guidelines.rst (renamed from python-guidelines.rst)0
-rw-r--r--orphaned/qa-0.9.4.rst (renamed from checklists/qa-0.9.4.rst)0
-rw-r--r--taler-developer-manual.rst8
-rw-r--r--taler-exchange-manual.rst179
20 files changed, 1376 insertions, 831 deletions
diff --git a/core/api-bank-conversion-info.rst b/core/api-bank-conversion-info.rst
index 322e9403..63856142 100644
--- a/core/api-bank-conversion-info.rst
+++ b/core/api-bank-conversion-info.rst
@@ -108,7 +108,7 @@ is used by wallets for withdrawals that involve a currency conversion.
* ``TALER_EC_GENERIC_PARAMETER_MALFORMED`` : both of the parameters have been provided or one of them is not a valid Taler amount.
* ``TALER_EC_GENERIC_CURRENCY_MISMATCH`` : the parameter is in the wrong currency.
:http:statuscode:`409 Conflict`:
- The amount is too small to be converted, either because it produces produce an amount less than zero, or because the server requires a higher minimum amount than that supplied.
+ The amount is too small to be converted because it produces an amount less than zero.
:http:statuscode:`501 Not implemented`:
This server does not support conversion, client should check config response.
@@ -154,7 +154,7 @@ is used by wallets for withdrawals that involve a currency conversion.
* ``TALER_EC_GENERIC_PARAMETER_MALFORMED`` : both of the parameters have been provided or one of them is not a valid Taler amount.
* ``TALER_EC_GENERIC_CURRENCY_MISMATCH`` : the parameter is in the wrong currency.
:http:statuscode:`409 Conflict`:
- The amount is too small to be converted, either because it produces produce an amount less than zero, or because the server requires a higher minimum amount than that supplied.
+ The amount is too small to be converted because it produces an amount less than zero.
:http:statuscode:`501 Not implemented`:
This server does not support conversion, client should check config response.
diff --git a/core/api-bank-wire.rst b/core/api-bank-wire.rst
index a76f5195..84184ec9 100644
--- a/core/api-bank-wire.rst
+++ b/core/api-bank-wire.rst
@@ -133,7 +133,8 @@ Making Transactions
// time period a transaction belongs to).
timestamp: Timestamp;
- // Opaque ID of the transaction that the bank has made.
+ // Opaque ID of the wire transfer initiation performed by the bank.
+ // It is different from the /history endpoints row_id.
row_id: SafeUint64;
}
@@ -429,6 +430,25 @@ exposed by bank gateways in production.
// time period a transaction belongs to).
timestamp: Timestamp;
- // Opaque ID of the transaction that the bank has made.
+ // Opaque ID of the wire transfer initiation performed by the bank.
+ // It is different from the /history endpoints row_id.
row_id: SafeUint64;
}
+
+
+Security Considerations
+=======================
+
+For implementors:
+
+* The withdrawal operation ID must contain enough entropy to be unguessable.
+
+Design:
+
+* The user must complete the 2FA step of the withdrawal in the context of their banking
+ app or online banking Website.
+ We explicitly reject any design where the user would have to enter a confirmation code
+ they get from their bank in the context of the wallet, as this would teach and normalize
+ bad security habits.
+
+
diff --git a/core/api-common.rst b/core/api-common.rst
index 521b2fc0..2208eb8d 100644
--- a/core/api-common.rst
+++ b/core/api-common.rst
@@ -255,6 +255,11 @@ hashed data. See `base32`_.
// 32-byte hash code.
type ShortHashCode = string;
+.. ts:def:: AccountAccessToken
+
+ // 32-byte nonce.
+ type AccountAccessToken = string;
+
.. ts:def:: WireSalt
// 16-byte salt.
@@ -758,6 +763,56 @@ denoting microseconds since the UNIX Epoch. ``UINT64_MAX`` represents "never".
uint64_t abs_value_us__; // in network byte order
};
+.. _LegalTrouble:
+
+451 Responses
+^^^^^^^^^^^^^
+
+When KYC operations are required, various endpoints may respond with a
+``451 Unavailable for Legal Reasons`` status code and a `LegitimizationNeededResponse`
+body.
+
+.. ts:def:: LegitimizationNeededResponse
+
+ // Implemented in this style since exchange
+ // protocol **v20**.
+ interface LegitimizationNeededResponse {
+
+ // Numeric `error code <error-codes>` unique to the condition.
+ // Should always be ``TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED``.
+ code: number;
+
+ // Human-readable description of the error, i.e. "missing parameter",
+ // "commitment violation", ... Should give a human-readable hint
+ // about the error's nature. Optional, may change without notice!
+ hint?: string;
+
+ // Hash of the payto:// account URI for which KYC
+ // is required.
+ h_payto: PaytoHash;
+
+ // Public key associated with the account. The client must sign
+ // the initial request for the KYC status using the corresponding
+ // private key. Will be either a reserve public key or a merchant
+ // (instance) public key.
+ //
+ // Absent if no public key is currently associated
+ // with the account and the client MUST thus first
+ // credit the exchange via an inbound wire transfer
+ // to associate a public key with the debited account.
+ account_pub?: EddsaPublicKey;
+
+ // Identifies a set of measures that were triggered and that are
+ // now preventing this operation from proceeding. Gives the
+ // account holder a starting point for understanding why the
+ // transaction was blocked and how to lift it. The account holder
+ // should use the number to check for the account's AML/KYC status
+ // using the ``/kyc-check/$REQUIREMENT_ROW`` endpoint.
+ requirement_row: Integer;
+
+ }
+
+
Cryptographic primitives
^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/core/api-corebank.rst b/core/api-corebank.rst
index 4a0288a4..f9ab7caa 100644
--- a/core/api-corebank.rst
+++ b/core/api-corebank.rst
@@ -188,6 +188,11 @@ Account Management
// Only admin can set this property.
debit_threshold?: Amount;
+ // If present, set a custom minimum cashout amount for this account.
+ // Only admin can set this property
+ // @since v4
+ min_cashout?: Amount;
+
// If present, enables 2FA and set the TAN channel used for challenges
// Only admin can set this property, other user can reconfig their account
// after creation.
@@ -220,6 +225,7 @@ Account Management
* ``TALER_EC_BANK_UNALLOWED_DEBIT`` : admin account does not have sufficient funds to grant bonus.
* ``TALER_EC_BANK_RESERVED_USERNAME_CONFLICT`` : a reserved username was attempted, like ``admin`` or ``bank``
* ``TALER_EC_BANK_NON_ADMIN_PATCH_DEBT_LIMIT`` : a non-admin user has tried to create an account with a customer debt limit.
+ * ``TALER_EC_BANK_NON_ADMIN_SET_MIN_CASHOUT`` : a non-admin user has tried to create an account with a custom min cashout amount.
* ``TALER_EC_BANK_NON_ADMIN_SET_TAN_CHANNEL`` : a non-admin user has tried to create an account with 2fa.
* ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED``: ``tan_channel`` is not supported, check bank config to find supported ones.
* ``TALER_EC_BANK_MISSING_TAN_INFO``: the user did not share any contact data where to send the TAN via ``tan_channel``.
@@ -233,28 +239,6 @@ Account Management
internal_payto_uri: string;
}
-.. _delete-account:
-
-.. http:delete:: /accounts/$USERNAME
-
- Delete the account whose username is ``$USERNAME``. The deletion
- succeeds only if the balance is *zero*. Typically only available to
- the administrator, but can be configured to allow ordinary users too.
-
- **Response:**
-
- :http:statuscode:`202 Accepted`:
- 2FA is required for this operation. This returns the `Challenge` response.
- :http:statuscode:`204 No content`:
- The account was successfully deleted.
- :http:statuscode:`401 Unauthorized`:
- Invalid credentials or missing rights.
- :http:statuscode:`404 Not found`:
- The account pointed by ``$USERNAME`` was not found.
- :http:statuscode:`409 Conflict`:
- * ``TALER_EC_BANK_RESERVED_USERNAME_CONFLICT`` : a reserved username was attempted, like ``admin`` or ``bank``.
- * ``TALER_EC_BANK_ACCOUNT_BALANCE_NOT_ZERO``: the account balance was not zero.
-
.. _account-reconfig:
.. http:patch:: /accounts/$USERNAME
@@ -288,6 +272,11 @@ Account Management
// Only admin can change this property.
debit_threshold?: Amount;
+ // If present, change the custom minimum cashout amount for this account.
+ // Only admin can set this property
+ // @since v4
+ min_cashout?: Amount;
+
// If present, enables 2FA and set the TAN channel used for challenges
tan_channel?: TanChannel;
}
@@ -306,6 +295,7 @@ Account Management
* ``TALER_EC_BANK_NON_ADMIN_PATCH_LEGAL_NAME`` : a non-admin user has tried to change their legal name.
* ``TALER_EC_BANK_NON_ADMIN_PATCH_CASHOUT`` : a non-admin user has tried to change their cashout account.
* ``TALER_EC_BANK_NON_ADMIN_PATCH_DEBT_LIMIT`` : a non-admin user has tried to change their debt limit.
+ * ``TALER_EC_BANK_NON_ADMIN_SET_MIN_CASHOUT`` : a non-admin user has tried to change their custom min cashout amount.
* ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED`` : ``tan_channel`` is not supported, check bank config to find supported ones.
* ``TALER_EC_BANK_MISSING_TAN_INFO`` : the user did not share any contact data where to send the TAN via ``tan_channel``.
@@ -343,6 +333,29 @@ Account Management
* ``TALER_EC_BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD``: a non-admin user has tried to change their password whihout providing the current one.
* ``TALER_EC_BANK_PATCH_BAD_OLD_PASSWORD`` : provided old password does not match current password.
+
+.. _delete-account:
+
+.. http:delete:: /accounts/$USERNAME
+
+ Delete the account whose username is ``$USERNAME``. The deletion
+ succeeds only if the balance is *zero*. Typically only available to
+ the administrator, but can be configured to allow ordinary users too.
+
+ **Response:**
+
+ :http:statuscode:`202 Accepted`:
+ 2FA is required for this operation. This returns the `Challenge` response.
+ :http:statuscode:`204 No content`:
+ The account was successfully deleted.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+ :http:statuscode:`404 Not found`:
+ The account pointed by ``$USERNAME`` was not found.
+ :http:statuscode:`409 Conflict`:
+ * ``TALER_EC_BANK_RESERVED_USERNAME_CONFLICT`` : a reserved username was attempted, like ``admin`` or ``bank``.
+ * ``TALER_EC_BANK_ACCOUNT_BALANCE_NOT_ZERO``: the account balance was not zero.
+
.. _account-list:
.. http:get:: /public-accounts
@@ -460,6 +473,11 @@ Account Management
// Number indicating the max debit allowed for the requesting user.
debit_threshold: Amount;
+ // Custom minimum cashout amount for this account.
+ // If null or absent, the global conversion fee is used.
+ // @since v4
+ min_cashout?: Amount;
+
// Is this account visible to anyone?
is_public: boolean;
@@ -513,6 +531,11 @@ Account Management
// Number indicating the max debit allowed for the requesting user.
debit_threshold: Amount;
+ // Custom minimum cashout amount for this account.
+ // If null or absent, the global conversion fee is used.
+ // @since v4
+ min_cashout?: Amount;
+
// Addresses where to send the TAN for transactions.
// Currently only used for cashouts.
// If missing, cashouts will fail.
@@ -883,9 +906,10 @@ Cashouts
The account pointed by ``$USERNAME`` was not found.
:http:statuscode:`409 Conflict`:
* ``TALER_EC_BANK_TRANSFER_REQUEST_UID_REUSED``: an operation with the same ``request_uid`` but different details has been submitted before.
- * ``TALER_EC_BANK_BAD_CONVERSION`` : exchange rate was calculated incorrectly by the client.
- * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : the account does not have sufficient funds.
- * ``TALER_EC_BANK_CONFIRM_INCOMPLETE`` : the user did not share any cashout payto to uri where to wire funds.
+ * ``TALER_EC_BANK_BAD_CONVERSION``: exchange rate was calculated incorrectly by the client.
+ * ``TALER_EC_BANK_BANK_CONVERSION_AMOUNT_TO_SMALL``: the amount of the cashout is too small.
+ * ``TALER_EC_BANK_UNALLOWED_DEBIT``: the account does not have sufficient funds.
+ * ``TALER_EC_BANK_CONFIRM_INCOMPLETE``: the user did not share any cashout payto to uri where to wire funds.
:http:statuscode:`501 Not Implemented`:
* ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED``: the chosen ``tan_channel`` is not currently supported.
* This server does not support conversion, client should check config response.
diff --git a/core/api-exchange.rst b/core/api-exchange.rst
index 4c5be000..fcd0122f 100644
--- a/core/api-exchange.rst
+++ b/core/api-exchange.rst
@@ -62,7 +62,7 @@ possibly by using HTTPS.
as well as the list of possible KYC requirements. This endpoint is largely
for the SPA for AML officers. Merchants should use ``/keys`` which also
contains the protocol version and currency.
- This specification corresponds to ``current`` protocol being **v19**.
+ This specification corresponds to ``current`` protocol being **v20**.
**Response:**
@@ -1323,19 +1323,188 @@ to allow exchange staff to monitor suspicious transactions
and freeze or unfreeze accounts suspected of money laundering.
-.. http:get:: /aml/$OFFICER_PUB/decisions/$STATE
+.. http:get:: /aml/$OFFICER_PUB/measures
- Obtain list of AML decisions (filtered by $STATE). ``$STATE`` must be either ``normal``, ``pending`` or ``frozen``.
+ 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.
- *Taler-AML-Officer-Signature*: The client must provide Base-32 encoded EdDSA signature with ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that this is merely a simple authentication mechanism, the details of the request are not protected by the signature.
+ This endpoint was introduced in protocol **v20**.
- :query delta: *Optional*. takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` are returned. Defaults to ``-20`` to return the last 20 entries (before ``start``).
- :query start: *Optional*. Row number threshold, see ``delta`` for its interpretation. Defaults to ``INT64_MAX``, namely the biggest row id possible in the database.
+ **Request:**
- **Response**
+ *Taler-AML-Officer-Signature*:
+ The client must provide Base-32 encoded EdDSA signature with
+ ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that
+ this is merely a simple authentication mechanism, the details of the
+ request are not protected by the signature.
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ Information about possible measures is returned in a
+ `AvailableMeasureSummary` object.
+
+ **Details:**
+
+ .. 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. Optional.
+ 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 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/$OFFICER_PUB/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.)
+
+ This endpoint was introduced in protocol **v20**.
+
+ **Request:**
+
+ *Taler-AML-Officer-Signature*:
+ The client must provide Base-32 encoded EdDSA signature with
+ ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that this
+ is merely a simple authentication mechanism, the details of the request are
+ not protected by the signature.
+
+ :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:**
+
+ :http:statuscode:`200 OK`:
+ The responds will be an `EventCounter` message.
+
+ **Details:**
+
+ .. ts:def:: EventCounter
+
+ interface EventCounter {
+ // Number of events of the specified type in
+ // the given range.
+ counter: Integer;
+ }
+
+
+.. http:get:: /aml/$OFFICER_PUB/decisions
+
+ **Request:**
+
+ *Taler-AML-Officer-Signature*:
+ The client must provide Base-32 encoded EdDSA signature with
+ ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that
+ this is merely a simple authentication mechanism, the details of the
+ request are not protected by the signature.
+
+ This endpoint was introduced in this form in protocol **v20**.
+
+ :query limit:
+ *Optional*. takes value of the form ``N (-N)``, so that at
+ most ``N`` values strictly older (younger) than ``start`` are returned.
+ Defaults to ``-20`` to return the last 20 entries (before ``start``).
+ :query offset:
+ *Optional*. Row number threshold, see ``delta`` for its
+ interpretation. Defaults to ``INT64_MAX``, namely the biggest row id
+ possible in the database.
+ :query h_payto:
+ *Optional*. Account selector. All matching accounts are returned if this
+ filter is absent, otherwise only decisions for this account.
+ :query active:
+ *Optional*. If set to yes, only return active decisions, if no only
+ decisions that have been superceeded. Do not give (or use "all") to
+ see all decisions regardless of activity status.
+ :query investigation:
+ *Optional*. If set to yes, only return accounts that are under
+ AML investigation, if no only accounts that are not under investigation.
+ Do not give (or use "all") to see all accounts regardless of
+ investigation status.
+
+ **Response:**
:http:statuscode:`200 OK`:
- The responds will be an `AmlRecords` message.
+ The responds will be an `AmlDecisions` message.
:http:statuscode:`204 No content`:
There are no matching AML records.
:http:statuscode:`403 Forbidden`:
@@ -1347,100 +1516,214 @@ and freeze or unfreeze accounts suspected of money laundering.
**Details:**
- .. ts:def:: AmlRecords
+ .. ts:def:: AmlDecisions
- interface AmlRecords {
+ interface AmlDecisions {
- // Array of AML records matching the query.
- records: AmlRecord[];
+ // Array of AML decisions matching the query.
+ records: AmlDecision[];
}
- .. ts:def:: AmlRecord
+ .. ts:def:: AmlDecision
- interface AmlRecord {
+ interface AmlDecision {
// Which payto-address is this record about.
// Identifies a GNU Taler wallet or an affected bank account.
h_payto: PaytoHash;
- // What is the current AML state.
- current_state: Integer;
+ // Row ID of the record. Used to filter by offset.
+ rowid: Integer;
- // Monthly transaction threshold before a review will be triggered
- threshold: Amount;
+ // When was the decision made?
+ decision_time: Timestamp;
- // RowID of the record.
- rowid: Integer;
+ // 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;
+
+ // What are the new rules?
+ limits: LegitimizationRuleSet;
+
+ // True if the account is under investigation by AML staff
+ // after this decision.
+ to_investigate: boolean;
+
+ // True if this is the active decision for the
+ // account.
+ is_active: boolean;
}
+ .. ts:def:: AccountProperties
-.. http:get:: /aml/$OFFICER_PUB/decision/$H_PAYTO
+ // 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.
+ interface AccountProperties {
- Obtain deails about an AML decision.
+ // True if this is a politically exposed account.
+ // Rules for classifying accounts as politically
+ // exposed are country-dependent.
+ pep?: boolean;
- *Taler-AML-Officer-Signature*: The client must provide Base-32 encoded EdDSA signature with ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that this is merely a simple authentication mechanism, the details of the request are not protected by the signature.
+ // True if this is a sanctioned account.
+ // Rules for classifying accounts as sanctioned
+ // are country-dependent.
+ sanctioned?: boolean;
- :query history: *Optional*. If set to yes, we return all historic decisions and not only the last one.
+ // True if this is a high-risk account.
+ // Rules for classifying accounts as at-risk
+ // are exchange operator-dependent.
+ high_risk?: boolean;
- **Response**
+ // Business domain of the account owner.
+ // The list of possible business domains is
+ // operator- or country-dependent.
+ business_domain?: string;
- :http:statuscode:`200 OK`:
- The responds will be an `AmlDecisionDetails` message.
- :http:statuscode:`204 No content`:
- There are no matching AML records for the given payto://-URI.
- :http:statuscode:`403 Forbidden`:
- The signature is invalid.
- :http:statuscode:`404 Not found`:
- The designated AML account is not known.
- :http:statuscode:`409 Conflict`:
- The designated AML account is not enabled.
+ // Is the client's account currently frozen?
+ is_frozen?: boolean;
- **Details:**
+ // Was the client's account reported to the authorities?
+ was_reported?: boolean;
+
+ }
+
+ .. ts:def:: LegitimizationRuleSet
+
+ interface LegitimizationRuleSet {
- .. ts:def:: AmlDecisionDetails
+ // When does this set of rules expire and
+ // we automatically transition to the successor
+ // measure?
+ expiration_time: Timestamp;
- interface AmlDecisionDetails {
+ // 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;
- // Array of AML decisions made for this account. Possibly
- // contains only the most recent decision if "history" was
- // not set to 'true'.
- aml_history: AmlDecisionDetail[];
+ // Legitimization rules that are to be applied
+ // to this account.
+ rules: KycRule[];
- // Array of KYC attributes obtained for this account.
- kyc_attributes: KycDetail[];
+ // Custom measures that KYC rules and the
+ // ``successor_measure`` may refer to.
+ custom_measures: { "$measure_name" : MeasureInformation; };
+
}
- .. ts:def:: AmlDecisionDetail
+ .. ts:def:: KycRule
- interface AmlDecisionDetail {
+ interface KycRule {
- // What was the justification given?
- justification: string;
+ // Type of operation to which the rule applies.
+ operation_type: string;
+
+ // The measures will be taken if the given
+ // threshold is crossed over the given timeframe.
+ threshold: Amount;
- // FIXME: review!
- // What is the new AML state.
- new_state: Integer;
+ // 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;
+
+ }
+
+.. http:get:: /aml/$OFFICER_PUB/attributes/$H_PAYTO
+
+ Obtain attributes obtained as part of AML/KYC processes for a
+ given account.
+
+ This endpoint was introduced in protocol **v20**.
+
+ **Request:**
- // When was this decision made?
- decision_time: Timestamp;
+ *Taler-AML-Officer-Signature*:
+ The client must provide Base-32 encoded EdDSA signature with
+ ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that
+ this is merely a simple authentication mechanism, the details of the
+ request are not protected by the signature.
+
+ :query limit:
+ *Optional*. takes value of the form ``N (-N)``, so that at
+ most ``N`` values strictly older (younger) than ``start`` are returned.
+ Defaults to ``-20`` to return the last 20 entries (before ``start``).
+ :query offset:
+ *Optional*. Row number threshold, see ``delta`` for its
+ interpretation. Defaults to ``INT64_MAX``, namely the biggest row id
+ possible in the database.
- // What is the new AML decision threshold (in monthly transaction volume)?
- new_threshold: Amount;
+ **Response:**
- // Who made the decision?
- decider_pub: AmlOfficerPublicKeyP;
+ :http:statuscode:`200 OK`:
+ The responds will be an `KycAttributes` message.
+ :http:statuscode:`204 No content`:
+ There are no matching KYC attributes.
+ :http:statuscode:`403 Forbidden`:
+ The signature is invalid.
+ :http:statuscode:`404 Not found`:
+ The designated AML account is not known.
+ :http:statuscode:`409 Conflict`:
+ The designated AML account is not enabled.
+
+ .. ts:def:: KycAttributes
+
+ interface KycAttributes {
+
+ // Matching KYC attribute history of the account.
+ details: KycAttributeCollectionEvent[];
}
- .. ts:def:: KycDetail
+ .. ts:def:: KycAttributeCollectionEvent
- interface KycDetail {
+ interface KycAttributeCollectionEvent {
+
+ // Row ID of the record. Used to filter by offset.
+ rowid: Integer;
// Name of the configuration section that specifies the provider
- // which was used to collect the KYC details
- // FIXME: review!
- provider_section: string;
+ // which was used to collect the attributes. NULL if they were
+ // just uploaded via a form by the account owner.
+ provider_section?: string;
// The collected KYC data. NULL if the attribute data could not
// be decrypted (internal error of the exchange, likely the
@@ -1450,9 +1733,6 @@ and freeze or unfreeze accounts suspected of money laundering.
// Time when the KYC data was collected
collection_time: Timestamp;
- // Time when the validity of the KYC data will expire
- expiration_time: Timestamp;
-
}
@@ -1487,17 +1767,17 @@ and freeze or unfreeze accounts suspected of money laundering.
// Human-readable justification for the decision.
justification: string;
- // At what monthly transaction volume should the
- // decision be automatically reviewed?
- new_threshold: Amount;
-
// Which payto-address is the decision about?
// Identifies a GNU Taler wallet or an affected bank account.
h_payto: PaytoHash;
- // What is the new AML state (e.g. frozen, unfrozen, etc.)
- // Numerical values are defined in `AmlDecisionState`.
- new_state: Integer;
+ // What are the new rules?
+ // New since protocol **v20**.
+ new_rules: LegitimizationRuleSet;
+
+ // True if the account should remain under investigation by AML staff.
+ // New since protocol **v20**.
+ keep_investigating: boolean;
// Signature by the AML officer over a `TALER_AmlDecisionPS`.
// Must have purpose ``TALER_SIGNATURE_MASTER_AML_KEY``.
@@ -1506,9 +1786,6 @@ and freeze or unfreeze accounts suspected of money laundering.
// When was the decision made?
decision_time: Timestamp;
- // Optional argument to impose new KYC requirements
- // that the customer has to satisfy to unblock transactions.
- kyc_requirements?: string[];
}
@@ -1769,7 +2046,7 @@ Batch Withdraw
The user should be redirected to the provided location to perform
the required KYC checks to open the account before withdrawing.
Afterwards, the request should be repeated.
- The response will be an `KycNeededRedirect` object.
+ The response will be an `LegitimizationNeededResponse` object.
Implementation note: internally, we need to
distinguish between upgrading the reserve to an
@@ -1857,29 +2134,6 @@ Batch Withdraw
}
- .. ts:def:: KycNeededRedirect
-
- interface KycNeededRedirect {
-
- // Numeric `error code <error-codes>` unique to the condition.
- // Should always be ``TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED``.
- code: number;
-
- // Human-readable description of the error, i.e. "missing parameter", "commitment violation", ...
- // Should give a human-readable hint about the error's nature. Optional, may change without notice!
- hint?: string;
-
- // Hash of the payto:// account URI that identifies
- // the account which is being KYCed.
- h_payto: PaytoHash;
-
- // Legitimization target that the merchant should
- // use to check for its KYC status using
- // the ``/kyc-check/$REQUIREMENT_ROW/...`` endpoint.
- requirement_row: Integer;
-
- }
-
.. ts:def:: WithdrawError
interface WithdrawError {
@@ -1986,7 +2240,7 @@ If so, the exchange will blindly sign ``n`` undisclosed coins from the request.
The user should be redirected to the provided location to perform
the required KYC checks to open the account before withdrawing.
Afterwards, the request should be repeated.
- The response will be an `KycNeededRedirect` object.
+ The response will be an `LegitimizationNeededResponse` object.
.. ts:def:: AgeWithdrawRequest
@@ -3970,6 +4224,7 @@ typically also view the balance.)
// Current AML state for the target account. Non-zero
// values indicate that the transfer is blocked due to
// AML enforcement.
+ // Removed in protocol **v20**.
aml_decision: Integer;
// True if the KYC check for the merchant has been
@@ -4465,7 +4720,7 @@ Wallet-to-wallet transfers
:http:statuscode:`451 Unavailable For Legal Reasons`:
This account has not yet passed the KYC checks.
The client must pass KYC checks before proceeding with the merge.
- The response will be an `KycNeededRedirect` object.
+ The response will be an `LegitimizationNeededResponse` object.
**Details:**
@@ -4576,7 +4831,7 @@ Wallet-to-wallet transfers
:http:statuscode:`451 Unavailable For Legal Reasons`:
This account has not yet passed the KYC checks.
The client must pass KYC checks before proceeding with the merge.
- The response will be an `KycNeededRedirect` object.
+ The response will be an `LegitimizationNeededResponse` object.
**Details:**
@@ -4869,6 +5124,17 @@ regulatory compliance.
.. http:post:: /kyc-wallet
+ 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.
+
Setup KYC identification for a wallet. Returns the KYC UUID.
This endpoint is used by compliant Taler wallets when they
are about to hit the balance threshold and thus need to have
@@ -4892,7 +5158,7 @@ regulatory compliance.
This response comes with a standard `ErrorDetail` response.
:http:statuscode:`451 Unavailable for Legal Reasons`:
The wallet must undergo a KYC check. A KYC ID was created.
- The response will be a `WalletKycUuid` object.
+ The response will be a `LegitimizationNeededResponse` object (changed in protocol **v20**).
**Details:**
@@ -4915,73 +5181,74 @@ regulatory compliance.
reserve_pub: EddsaPublicKey;
}
- .. ts:def:: WalletKycUuid
+.. http:get:: /kyc-check/$REQUIREMENT_ROW
- interface WalletKycUuid {
+ Checks the KYC status of a particular payment target and possibly begins a
+ KYC process by allowing the customer to choose the next KYC measure to
+ satisfy. This endpoint is typically used by wallets or merchants that
+ have been told that a transaction is not happening because it triggered
+ some KYC/AML measure and now want to check how the KYC/AML
+ requirement could be fulfilled (or whether it already has been
+ statisfied and the operation can now proceed). Long-polling may be used
+ to instantly observe a change in the KYC requirement status.
- // UUID that the wallet should use when initiating
- // the KYC check.
- requirement_row: number;
-
- // Hash of the payto:// account URI for the wallet.
- h_payto: PaytoHash;
-
- }
+ The requirement row of the ``/kyc-check/`` endpoint encodes the
+ legitimization measure's serial number. It is returned in
+ `LegitimizationNeededResponse` responses via the ``requirement_row`` field.
+ Given a valid pair of requirement row and account owner signature, the
+ ``/kyc-check/`` endpoint returns either just the 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. 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. Clients
+ that received a 202 status code may repeat the request and use long-polling
+ to detect a change of the HTTP status.
-.. http:get:: /kyc-check/$REQUIREMENT_ROW/$H_PAYTO/$USERTYPE
+ This endpoint exists in this specific form only since protocol **v20**.
- Checks the KYC status of a particular payment target and possibly begins the
- KYC process. This endpoint is used by wallets or merchants that have been
- told about a KYC requirement and now want to check if the KYC requirement
- has been fulfilled. Long-polling may be used to instantly observe a change
- in the KYC requirement status.
+ **Request:**
- Returns the current KYC status of the requirement process and, if negative,
- returns the URL where the KYC process can be initiated. The
- ``$REQUIREMENT_ROW`` must have been returned previously from an exchange API
- endpoint that determined that KYC was needed. The ``$H_PATYO`` must be the
- hash of the "payto://" URI of the payment target. The ``$USERTYPE`` states
- whether the entity to perform the KYC is an "individual" or a "business".
+ *Account-Owner-Signature*:
- **Request:**
+ The client must provide Base-32 encoded EdDSA signature with
+ ``$ACCOUNT_PRIV``, affirming the desire to obtain KYC data. Note that
+ this is merely a simple authentication mechanism, the details of the
+ request are not protected by the signature. The ``$ACCOUNT_PRIV`` is
+ either the (wallet long-term) reserve private key or the merchant instance
+ private key.
:query timeout_ms=NUMBER: *Optional.* If specified, the exchange will
- wait up to ``timeout_ms`` milliseconds if the payment target
- is currently not legitimized. Ignored if the payment target
- is already legitimized. Note that the legitimization would be
- triggered by another request to the same endpoint with a valid
- ``token``.
+ wait up to ``timeout_ms`` milliseconds if the requirement continues
+ to be mandatory provisioning of KYC data by the client.
+ Ignored if the HTTP status code is already ``200 Ok``. Note that
+ clients cannot long-poll for AML staff actions, so status information
+ about an account being under AML review needs to be requested
+ periodically.
**Response:**
:http:statuscode:`200 Ok`:
- The KYC operation succeeded, the exchange confirms that the
- payment target already authorized to transact.
- The response will be an `AccountKycStatus` object.
+ No mandatory KYC actions are required by the client at this time.
+ The client *may* still visit the KYC URL to initiate voluntary checks.
+ The response will be an `AccountKycStatus` object which specifies
+ restrictions that currently apply to the account. If the
+ client attempts to exceed *soft* limits, the status may change
+ to a ``202 Accepted``. Hard limits cannot be lifted by passing KYC checks.
:http:statuscode:`202 Accepted`:
- The user should be redirected to the provided location to perform
+ The account holder performed an operation that would have crossed
+ *soft* limits and must be redirected to the provided location to perform
the required KYC checks to satisfy the legal requirements. Afterwards, the
``/kyc-check/`` request should be repeated to check whether the
user has completed the process.
- The response will be an `AccountKycRedirect` object.
+ The response will be an `AccountKycStatus` object.
:http:statuscode:`204 No content`:
The exchange is not configured to perform KYC and thus
the legal requirements are already satisfied.
- :http:statuscode:`402 Payment Required`:
- The client must pay the KYC fee for the KYC process.
- **This is currently not implemented, see #7365.**
:http:statuscode:`403 Forbidden`:
- The provided hash does not match the payment target.
+ The provided signature is not acceptable for the requirement row.
:http:statuscode:`404 Not found`:
- The payment target is unknown.
- :http:statuscode:`451 Unavailable for Legal Reasons`:
- The transaction cannot be completed due to AML rules.
- Thus, the operation is currently not stuck on KYC, but
- on exchange staff performing their AML review. The user
- should be told to wait and/or contact the exchange operator
- if the situation persists.
- The response will be a `AccountAmlBlocked` object.
+ The requirement row is unknown.
**Details:**
@@ -4989,69 +5256,268 @@ regulatory compliance.
interface AccountKycStatus {
- // Details about the KYC check that the user
- // passed.
- kyc_details: KycDetails;
+ // Current AML state for the target account. True if
+ // operations are not happening due to staff processing
+ // paperwork *or* due to legal requirements (so the
+ // client cannot do anything but wait).
+ //
+ // Note that not every AML staff action may be legally
+ // exposed to the client, so this is merely a hint that
+ // a client should be told that AML staff is currently
+ // reviewing the account. AML staff *may* review
+ // accounts without this flag being set!
+ aml_review: boolean;
+
+ // Access token needed to construct the ``/kyc-spa/``
+ // URL that the user should open in a browser to
+ // proceed with the KYC process (optional if the status
+ // type is ``200 Ok``, mandatory if the HTTP status
+ // is ``202 Accepted``).
+ access_token: AccountAccessToken;
+
+ // Array with limitations that currently apply to this
+ // account and that may be increased or lifted if the
+ // KYC check is passed.
+ // Note that additional limits *may* exist and not be
+ // communicated to the client. If such limits are
+ // reached, this *may* be indicated by the account
+ // going into ``aml_review`` state. However, it is
+ // also possible that the exchange may legally have
+ // to deny operations without being allowed to provide
+ // any justification.
+ // The limits should be used by the client to
+ // possibly structure their operations (e.g. withdraw
+ // what is possible below the limit, ask the user to
+ // pass KYC checks or withdraw the rest after the time
+ // limit is passed, warn the user to not withdraw too
+ // much or even prevent the user from generating a
+ // request that would cause it to exceed hard limits).
+ limits?: AccountLimit[];
+
+ }
+
+ .. ts:def:: AccountLimit
+
+ interface AccountLimit {
+
+ // Operation that is limited.
+ // Must be one of "WITHDRAW", "DEPOSIT", "P2P-RECEIVE"
+ // or "WALLET-BALANCE".
+ operation_type: string;
+
+ // Timeframe during which the limit applies.
+ timeframe: RelativeTime;
+
+ // Maximum amount allowed during the given timeframe.
+ // Zero if the operation is simply forbidden.
+ threshold: Amount;
- // Current time of the exchange, used as part of
- // what the exchange signs over.
- now: Timestamp;
+ // True if this is a soft limit that could be raised
+ // by passing KYC checks. Clients *may* deliberately
+ // try to cross limits and trigger measures resulting
+ // in 451 responses to begin KYC processes.
+ // Clients that are aware of hard limits *should*
+ // inform users about the hard limit and prevent flows
+ // in the UI that would cause violations of hard limits.
+ soft_limit: boolean;
+ }
+
+.. http:get:: /kyc-spa/$ACCESS_TOKEN
+.. http:get:: /kyc-spa/$FILENAME
+
+ A set of ``/kyc-spa/$ACCESS_TOKEN`` GET endpoints is created per account
+ hash that serves the KYC SPA. This is where the ``/kyc-check/`` endpoint
+ will in principle redirect clients. The KYC SPA will use the
+ ``$ACCESS_TOKEN`` of its URL to initialize itself via the
+ ``/kyc-info/$ACCESS_TOKEN`` endpoint family. The KYC SPA may download
+ additional resources via ``/kyc-spa/$FILENAME``. The filenames must not
+ match base32-encoded 256-bit values.
+
+ This endpoint was introduced in protocol **v20**.
+
+
+.. http:get:: /kyc-info/$ACCESS_TOKEN
+
+ The ``/kyc-info/$ACCESS_TOKEN`` endpoints are created per client
+ account hash (but access controlled via a unique target token)
+ 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.
+
+ This endpoint was introduced in protocol **v20**.
- // EdDSA signature of the exchange affirming the account
- // is KYC'ed, must be of purpose
- // ``TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS``
- // and over ``TALER_AccountSetupStatusSignaturePS``.
- exchange_sig: EddsaSignature;
+ **Request:**
- // public key used to create the signature.
- exchange_pub: EddsaPublicKey;
+ *If-None-Match*:
+ The client MAY provide an ``If-None-Match`` header with an ETag.
- // Current AML state for the target account. Non-zero
- // values indicate that the transfer is blocked due to
- // AML enforcement.
- aml_status: Integer;
+ :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 status.
+
+ **Response:**
+
+ *Etag*: Will be set to the serial ID of the measure. Used for long-polling (only for 200 OK responses).
+ :http:statuscode:`200 OK`:
+ The body is a `KycProcessClientInformation`.
+ :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.
+
+
+ **Details:**
+
+ .. 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:: AccountKycRedirect
+ .. ts:def:: KycRequirementInformation
- interface AccountKycRedirect {
+ interface KycRequirementInformation {
- // URL that the user should open in a browser to
- // proceed with the KYC process.
- kyc_url: string;
+ // 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;
- // Current AML state for the target account. Non-zero
- // values indicate that the transfer is blocked due to
- // AML enforcement.
- aml_status: Integer;
+ // 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". The
+ // ``$ID`` value may itself contain ``/`` or ``?`` and
+ // basically encode any URL path (and optional arguments).
+ id?: string;
}
- .. ts:def:: AccountAmlBlocked
+ .. ts:def:: KycCheckInformation
- interface AccountAmlBlocked {
+ // Since **vATTEST**.
+ interface KycCheckInformation {
- // Current AML state for the target account. Non-zero
- // values indicate that the transfer is blocked due to
- // AML enforcement.
- aml_status: Integer;
+ // English description of the check.
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized
+ // description texts.
+ description_i18n ?: { [lang_tag: string]: string };
+ // FIXME: is the above in any way sufficient
+ // to begin the check? Do we not need at least
+ // something more??!?
}
- .. ts:def:: KycDetails
- // Object that specifies which KYC checks are satisfied.
- interface KycDetails {
+.. 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``. In practice,
+ ``$ID`` will encode both the ``$ACCESS_TOKEN`` and the index of the selected
+ measure (but this should be irrelevant for the client).
+
+ This endpoint was introduced in protocol **v20**.
+
+ **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 Request Entity 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. In
+ practice, ``$ID`` will encode both the ``$ACCESS_TOKEN`` and the index of
+ the selected measure (but this should be irrelevant for the client).
+
+ **Request:**
+
+ Use empty JSON body for now.
- // Keys are the names of the check(s).
- // The values are for now always empty objects.
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ The KYC process was successfully initiated. The URL is in a
+ `KycProcessStartInformation` object.
+ :http:statuscode:`404 Not Found`:
+ The ``$ID`` is unknown to the exchange.
+
+ **Details:**
+ .. ts:def:: KycProcessStartInformation
+
+ interface KycProcessStartInformation {
+
+ // URL to open.
+ redirect_url: string;
}
+ .. 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/$PROVIDER_SECTION?state=$H_PAYTO
- Endpoint accessed from the user's browser at the *end* of a
+ Upon completion of the process at the external KYC provider, the provider
+ must redirect the client (browser) to trigger a GET request to a new
+ ``/kyc-proof/$H_PAYTO/$PROVIDER_SECTION`` 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 redirect the user to the KYC
+ SPA. This endpoint deliberately does not use the ``$ACCESS_TOKEN`` as the
+ external KYC provider should not learn that token.
+
+ This endpoint is thus accessed from the user's browser at the *end* of a
KYC process, possibly providing the exchange with additional
credentials to obtain the results of the KYC process.
Specifically, the URL arguments should provide
@@ -5071,8 +5537,10 @@ regulatory compliance.
If the KYC plugin logic is OAuth 2.0, the query parameters are:
- :query code=CODE: OAuth 2.0 code argument.
- :query state=STATE: OAuth 2.0 state argument with the H_PAYTO.
+ :query code=CODE:
+ OAuth 2.0 code argument.
+ :query state=STATE:
+ OAuth 2.0 state argument with the H_PAYTO.
.. note::
@@ -5176,7 +5644,7 @@ designated account.
:http:statuscode:`451 Unavailable For Legal Reasons`:
This account has not yet passed the KYC checks.
The client must pass KYC checks before the reserve can be opened.
- The response will be an `KycNeededRedirect` object.
+ The response will be an `LegitimizationNeededResponse` object.
**Details:**
@@ -5392,7 +5860,7 @@ designated account.
This account has not yet passed the KYC checks, hence wiring
funds to a non-origin account is not allowed.
The client must pass KYC checks before the reserve can be opened.
- The response will be an `KycNeededRedirect` object.
+ The response will be an `LegitimizationNeededResponse` object.
**Details:**
diff --git a/core/api-merchant.rst b/core/api-merchant.rst
index 3fe808b3..e06b262b 100644
--- a/core/api-merchant.rst
+++ b/core/api-merchant.rst
@@ -342,6 +342,11 @@ Making the payment
// payment.
pos_confirmation?: string;
+ // Signed tokens. Returned in the same order as the
+ // token envelopes were provided in the request.
+ // @since protocol **vSUBSCRIBE**
+ token_sigs?: SignedTokenEnvelope[];
+
}
.. ts:def:: PayRequest
@@ -368,6 +373,46 @@ Making the payment
}
+ .. ts:def:: SignedTokenEnvelope
+
+ interface SignedTokenEnvelope {
+
+ // Blind signature made by the merchant.
+ blind_sig: TokenIssueBlindSig;
+
+ // Hash of the token issue public key.
+ h_issue: HashCode;
+
+ }
+
+ .. ts:def:: TokenIssueBlindSig
+
+ type TokenIssueBlindSig = RSATokenIssueBlindSig | CSTokenIssueBlindSig;
+
+ .. ts:def:: RSATokenIssueBlindSig
+
+ interface RSATokenIssueBlindSig {
+ cipher: "RSA";
+
+ // (blinded) RSA signature
+ blinded_rsa_signature: BlindedRsaSignature;
+ }
+
+ .. ts:def:: CSTokenIssueBlindSig
+
+ interface CSTokenIssueBlindSig {
+ type: "CS";
+
+ // Signer chosen bit value, 0 or 1, used
+ // in Clause Blind Schnorr to make the
+ // ROS problem harder.
+ b: Integer;
+
+ // Blinded scalar calculated from c_b.
+ s: Cs25519Scalar;
+
+ }
+
.. ts:def:: PayWalletData
interface PayWalletData {
@@ -444,10 +489,22 @@ Making the payment
.. ts:def:: TokenEnvelope
+ interface TokenEnvelope {
+
+ // Blinded token use public key.
+ token_ev: BlindedTokenEnvelope;
+
+ // Hash of the token issue public key.
+ h_issue: HashCode;
+
+ }
+
+ .. ts:def:: BlindedTokenEnvelope
+
// This type depends on the cipher used to sign token families. This is
// configured by the merchant and defined for each token family in the
// contract terms.
- type TokenEnvelope = RSATokenEnvelope | CSTokenEnvelope;
+ type BlindedTokenEnvelope = RSATokenEnvelope | CSTokenEnvelope;
.. ts:def:: RSATokenEnvelope
diff --git a/core/api-terminal.rst b/core/api-terminal.rst
index 5eaf4b5d..91d9b7e6 100644
--- a/core/api-terminal.rst
+++ b/core/api-terminal.rst
@@ -74,6 +74,11 @@ Config
// Terminal provider display name to be used in user interfaces.
provider_name: string;
+ // The currency supported by this Terminal-API
+ // must be the same as the currency specified
+ // in the currency field of the wire gateway config
+ currency: string;
+
// Wire transfer type supported by the terminal.
// FIXME: needed?
wire_type: string;
@@ -311,6 +316,28 @@ Config
:http:statuscode:`404 Not found`:
The operation was not found.
+.. http:delete:: /withdrawals/$WITHDRAWAL_ID/abort
+
+ Aborts ``WITHDRAWAL_ID`` operation. Has no effect on an already aborted
+ operation. This endpoint can be used by the terminal if the terminal aborts
+ the transaction, ensuring that the operation is also aborted at the
+ bank.
+
+ **Request:**
+
+ The request body is empty.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The withdrawal operation has been aborted.
+ :http:statuscode:`404 Not found`:
+ The withdrawal operation was not found.
+ :http:statuscode:`409 Conflict`:
+ The withdrawal operation has been confirmed previously and
+ can't be aborted.
+
+
Endpoints for Integrated Sub-APIs
---------------------------------
diff --git a/design-documents/023-taler-kyc.rst b/design-documents/023-taler-kyc.rst
index c20844b3..b0ee1750 100644
--- a/design-documents/023-taler-kyc.rst
+++ b/design-documents/023-taler-kyc.rst
@@ -200,7 +200,7 @@ user for *voluntary* KYC processes related to attestation (#7365).
Proposed Solution
=================
-The main state of an account is represented by a set of `KycRules` (the
+The main state of an account is represented by a set of `KYC rules <KycRule>` (the
`LegitimizationRuleSet`) which specify the current *rules* to apply to
transactions involving the account. Rules can *exposed* to the account owner,
or can be secret. Each *rule* specifies certain *conditions* which, if met,
@@ -431,48 +431,9 @@ expose merchant public key to SPA for wire transfer if needed for KYC.
^^^^^^^^^^^^
When KYC operations are required, various endpoints may respond with a
-``451 Unavailable for Legal Reasons`` status code and a `KycNeededRedirect`
+``451 Unavailable for Legal Reasons`` status code and a `LegitimziationNeededResponse`
body.
- .. ts:def:: KycNeededRedirect
-
- interface KycNeededRedirect {
-
- // Numeric `error code <error-codes>` unique to the condition.
- // Should always be ``TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED``.
- code: number;
-
- // Human-readable description of the error, i.e. "missing parameter",
- // "commitment violation", ... Should give a human-readable hint
- // about the error's nature. Optional, may change without notice!
- hint?: string;
-
- // Hash of the payto:// account URI for which KYC
- // is required.
- h_payto: PaytoHash;
-
- // Public key associated with the account. The client must sign
- // the initial request for the KYC status using the corresponding
- // private key. Will be either a reserve public key or a merchant
- // (instance) public key.
- //
- // Absent if no public key is currently associated
- // with the account and the client MUST thus first
- // credit the exchange via an inbound wire transfer
- // to associate a public key with the debited account.
- account_pub?: EddsaPublicKey;
-
- // Identifies a set of measures that were triggered and that are
- // now preventing this operation from proceeding. Gives the
- // account holder a starting point for understanding why the
- // transaction was blocked and how to lift it. The account holder
- // should use the number to check for the account's AML/KYC status
- // using the ``/kyc-check/$REQUIREMENT_ROW`` endpoint.
- requirement_row: Integer;
-
- }
-
-
New endpoints
^^^^^^^^^^^^^
@@ -489,7 +450,7 @@ New endpoints
The requirement row of the ``/kyc-check/`` endpoint encodes the
legitimization measure's serial number. It is returned in
- `KycNeededRedirect` responses via the ``requirement_row`` field.
+ `LegitimizationNeededResponse` responses via the ``requirement_row`` field.
Given a valid pair of requirement row and account owner signature, the
``/kyc-check/`` endpoint returns either just the KYC status or redirects the
@@ -543,79 +504,6 @@ New endpoints
:http:statuscode:`404 Not found`:
The requirement row is unknown.
- **Details:**
-
- .. ts:def:: AccountKycStatus
-
- interface AccountKycStatus {
-
- // Current AML state for the target account. True if
- // operations are not happening due to staff processing
- // paperwork *or* due to legal requirements (so the
- // client cannot do anything but wait).
- //
- // Note that not every AML staff action may be legally
- // exposed to the client, so this is merely a hint that
- // a client should be told that AML staff is currently
- // reviewing the account. AML staff *may* review
- // accounts without this flag being set!
- aml_review: boolean;
-
- // Access token needed to construct the ``/kyc-spa/``
- // URL that the user should open in a browser to
- // proceed with the KYC process (optional if the status
- // type is ``200 Ok``, mandatory if the HTTP status
- // is ``202 Accepted``).
- access_token: AccountAccessToken;
-
- // Array with limitations that currently apply to this
- // account and that may be increased or lifted if the
- // KYC check is passed.
- // Note that additional limits *may* exist and not be
- // communicated to the client. If such limits are
- // reached, this *may* be indicated by the account
- // going into ``aml_review`` state. However, it is
- // also possible that the exchange may legally have
- // to deny operations without being allowed to provide
- // any justification.
- // The limits should be used by the client to
- // possibly structure their operations (e.g. withdraw
- // what is possible below the limit, ask the user to
- // pass KYC checks or withdraw the rest after the time
- // limit is passed, warn the user to not withdraw too
- // much or even prevent the user from generating a
- // request that would cause it to exceed hard limits).
- limits?: AccountLimit[];
-
- }
-
- .. ts:def:: AccountLimit
-
- interface AccountLimit {
-
- // Operation that is limited.
- // Must be one of "WITHDRAW", "DEPOSIT", "P2P-RECEIVE"
- // or "WALLET-BALANCE".
- operation_type: string;
-
- // Timeframe during which the limit applies.
- timeframe: RelativeTime;
-
- // Maximum amount allowed during the given timeframe.
- // Zero if the operation is simply forbidden.
- threshold: Amount;
-
- // True if this is a soft limit that could be raised
- // by passing KYC checks. Clients *may* deliberately
- // try to cross limits and trigger measures resulting
- // in 451 responses to begin KYC processes.
- // Clients that are aware of hard limits *should*
- // inform users about the hard limit and prevent flows
- // in the UI that would cause violations of hard limits.
- soft_limit: boolean;
- }
-
-
.. http:get:: /kyc-spa/$ACCESS_TOKEN
.. http:get:: /kyc-spa/$FILENAME
@@ -656,72 +544,13 @@ New endpoints
**Response:**
+ *Etag*: Will be set to the serial ID of the measure. Used for long-polling (only for 200 OK responses).
+
: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". The
- // ``$ID`` value may itself contain ``/`` or ``?`` and
- // basically encode any URL path (and optional arguments).
- id?: string;
-
- }
-
- .. ts:def:: KycCheckInformation
-
- // Since **vATTEST**.
- interface KycCheckInformation {
-
- // 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.
@@ -749,7 +578,7 @@ New endpoints
The ``$ID`` is unknown to the exchange.
:http:statuscode:`409 Conflict`:
The upload conflicts with a previous upload.
- :http:statuscode:`413 Content Too Large`:
+ :http:statuscode:`413 Request Entity Too Large`:
The body is too large.
.. http:post:: /kyc-start/$ID
@@ -771,16 +600,6 @@ New endpoints
The KYC process was successfully initiated. The URL is in a
`KycProcessStartInformation` object.
- **Details:**
-
- .. ts:def:: KycProcessStartInformation
-
- interface KycProcessStartInformation {
-
- // URL to open.
- redirect_url: string;
- }
-
:http:statuscode:`404 Not Found`:
The ``$ID`` is unknown to the exchange.
@@ -913,29 +732,7 @@ New endpoints
This response comes with a standard `ErrorDetail` response.
:http:statuscode:`451 Unavailable for Legal Reasons`:
The wallet must undergo a KYC check. A KYC ID was created.
- The response will be a `KycNeededRedirect` object.
-
- **Details:**
-
- .. ts:def:: WalletKycRequest
-
- interface WalletKycRequest {
-
- // Balance threshold (not necessarily exact balance)
- // to be crossed by the wallet that (may) trigger
- // additional KYC requirements.
- balance: Amount;
-
- // EdDSA signature of the wallet affirming the
- // request, must be of purpose
- // ``TALER_SIGNATURE_WALLET_ACCOUNT_SETUP``
- reserve_sig: EddsaSignature;
-
- // long-term wallet reserve-account
- // public key used to create the signature.
- reserve_pub: EddsaPublicKey;
- }
-
+ The response will be a `LegitimizationNeededResponse` object.
.. http:get:: /aml/$OFFICER_PUB/measures
@@ -959,86 +756,6 @@ New endpoints
Information about possible measures is returned in a
`AvailableMeasureSummary` object.
- **Details:**
-
- .. 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. Optional.
- 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 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/$OFFICER_PUB/kyc-statistics/$NAME
Returns the number of KYC events matching the given event type ``$NAME`` in
@@ -1064,13 +781,8 @@ New endpoints
**Response:**
- .. ts:def:: EventCounter
-
- interface EventCounter {
- // Number of events of the specified type in
- // the given range.
- counter: Integer;
- }
+ :http:statuscode:`200 OK`:
+ The responds will be an `EventCounter` message.
.. http:get:: /aml/$OFFICER_PUB/decisions
@@ -1116,31 +828,6 @@ New endpoints
:http:statuscode:`409 Conflict`:
The designated AML account is not enabled.
- **Details:**
-
- .. ts:def:: AmlDecisions
-
- interface AmlDecisions {
-
- // Array of AML decisions matching the query.
- records: AmlDecisions[];
- }
-
- .. ts:def:: AmlRecord
-
- interface AmlRecord {
-
- // Which payto-address is this record about.
- // Identifies a GNU Taler wallet or an affected bank account.
- h_payto: PaytoHash;
-
- // Row ID of the record. Used to filter by offset.
- rowid: Integer;
-
- // FIXME: more fields here!
- }
-
-
.. http:get:: /aml/$OFFICER_PUB/attributes/$H_PAYTO
Obtain attributes obtained as part of AML/KYC processes for a
@@ -1176,40 +863,7 @@ New endpoints
:http:statuscode:`409 Conflict`:
The designated AML account is not enabled.
- .. ts:def:: KycAttributes
-
- interface KycAttributes {
-
- // Matching KYC attribute history of the account.
- details: KycDetail[];
-
- }
-
- .. ts:def:: KycDetail
-
- // FIXME: bad name?
- interface KycDetail {
-
- // Row ID of the record. Used to filter by offset.
- rowid: Integer;
-
- // Name of the configuration section that specifies the provider
- // which was used to collect the attributes. NULL if they were
- // just uploaded via a form by the account owner.
- provider_section?: string;
-
- // The collected KYC data. NULL if the attribute data could not
- // be decrypted (internal error of the exchange, likely the
- // attribute key was changed).
- attributes?: Object;
-
- // Time when the KYC data was collected
- collection_time: Timestamp;
-
- }
-
-
- .. http:post:: /aml/$OFFICER_PUB/decision
+.. http:post:: /aml/$OFFICER_PUB/decision
Make an AML decision. Triggers the respective action and
records the justification.
@@ -1231,35 +885,6 @@ New endpoints
The designated AML account is not enabled or a more recent
decision was already submitted.
- **Details:**
-
- .. ts:def:: AmlDecision
-
- interface AmlDecision {
-
- // Human-readable justification for the decision.
- justification: string;
-
- // Which payto-address is the decision about?
- // Identifies a GNU Taler wallet or an affected bank account.
- h_payto: PaytoHash;
-
- // What are the new rules?
- new_rules: LegitimizationRuleSet;
-
- // True if the account should remain under investigation by AML staff.
- bool keep_investigating;
-
- // When was the decision made?
- decision_time: Timestamp;
-
- // Signature by the AML officer over a `TALER_AmlDecisionPS`.
- // Must have purpose ``TALER_SIGNATURE_MASTER_AML_KEY``.
- officer_sig: EddsaSignature;
-
- }
-
-
Modifications to existing endpoints
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1311,17 +936,6 @@ description of the high-level process for different providers.
# Which plugin is responsible for this provider?
LOGIC = PLUGIN_NAME
- # 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.:
- AUTHORIZATION_TOKEN = superdupersecret
-
- # Other logic-specific internal options (example):
- FORM_ID = business_legi_form
-
# 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
@@ -1334,6 +948,17 @@ description of the high-level process for different providers.
# (when run regularly).
CONVERTER = taler-exchange-helper-$NAME
+ # 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.:
+ AUTHORIZATION_TOKEN = superdupersecret
+
+ # Other logic-specific internal options (example):
+ FORM_ID = business_legi_form
+
Configuration of possible KYC/AML checks
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1364,6 +989,7 @@ providers, one per configuration section:
VOLUNTARY = YES/NO
# Provider id, present only if type is LINK.
+ # Refers to a ``kyc-provider-$PROVIDER_ID`` section.
PROVIDER_ID = id
# Name of the SPA form, if type is FORM
@@ -1381,7 +1007,7 @@ providers, one per configuration section:
DESCRIPTION_I18N = "{"en":"Upload scan of your passport"}"
# ';'-separated list of fields that the CONTEXT must
- # provided as inputs to this check. For example,
+ # provide 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
@@ -1391,8 +1017,11 @@ providers, one per configuration section:
# Description of the outputs provided by the check.
# Basically, the check's output is expected to
- # provide the following fields as inputs into
+ # provide the following fields as attribute inputs into
# a subsequent AML program.
+ # Only given for type FORM; INFO never has any outputs,
+ # and for type LINK we can obtain the same information
+ # from the CONVERTER via ``--list-outputs``.
OUTPUTS = business_name street city country registration
# **original** measure to take if the check fails
@@ -1422,7 +1051,7 @@ configuration section:
[kyc-rule-$RULE_NAME]
- # Operation that triggers this legitimization.
+ # Operation that triggers this rule.
# Must be one of WITHDRAW, DEPOSIT, P2P-RECEIVE
# or WALLET-BALANCE.
OPERATION_TYPE = WITHDRAW
@@ -1436,8 +1065,8 @@ configuration section:
# (under this set of rules).
NEXT_MEASURES = SWISSNESS KYB
- # "yes" if all NEXT_MEASURES will eventually need
- # to be satisfied, "no" if the user has a choice between
+ # "YES" if all NEXT_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". YES for "and".
@@ -1450,7 +1079,7 @@ configuration section:
# Defaults to NO if not set.
EXPOSED = YES
- # Threshold amount above which the legitimization is
+ # Threshold amount above which the rule is
# triggered. The total must be exceeded in the given
# timeframe.
THRESHOLD = KUDOS:100
@@ -1460,7 +1089,7 @@ configuration section:
# Ignored for WALLET-BALANCE. Can be 'forever'.
TIMEFRAME = 30 days
- # Enabled (default is NO)
+ # Set to YES to enable the rule (default is NO)
ENABLED = NO
@@ -1487,113 +1116,6 @@ AML programs are helper programs that can:
This is the default behavior if no command-line switches
are provided.
-.. 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.
- aml_history: AmlDecisionDetail[];
-
- // JSON array with the results of historic
- // KYC data about the account.
- kyc_history: KycDetail[];
-
- }
-
-.. ts:def:: AmlOutcome
-
- 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;
-
- }
-
-.. ts:def:: KycRule
-
- interface KycRule {
-
- // Type of operation to which the rule applies.
- operation_type: string;
-
- // The measures will be taken if the given
- // threshold is crossed over the given timeframe.
- threshold: Amount;
-
- // 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[];
-
- // 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;
-
- // 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;
- }
-
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
@@ -1646,8 +1168,9 @@ Finally, the configuration specifies a set of
# just an empty JSON object if there is none.
CONTEXT = {"choices":["individual","business"]}
- # Program to run on the context and check data to
+ # Program name to run on the context and check data to
# determine the outcome and next measure.
+ # Refers to a ``[aml-program-$PROG_NAME]`` section name.
PROGRAM = taler-aml-program
If no ``CHECK_NAME`` is provided at all, the AML ``PROGRAM`` is to be run
@@ -1732,16 +1255,20 @@ on GET ``/deposits/`` with the respective legitimization requirement row.
,access_token BYTEA NOT NULL UNIQUE CHECK (LENGTH(access_token)=32)
REFERENCES wire_targets (access_token)
,start_time INT8 NOT NULL
- ,jmeasures TEXT NOT NULL
+ ,jmeasures TEXT NOT NULL -- FIXME: rename to jrule?
,display_priority INT4 NOT NULL
,is_finished BOOL NOT NULL DEFAULT(FALSE)
)
PARTITION BY HASH (access_token);
+ COMMENT ON TABLE legitimization_measures
+ IS 'Rules that have been triggered for the account (FIXME: check this is consistent with usage)';
COMMENT ON COLUMN legitimization_measures.access_token
IS 'Used to uniquely identify the account and as a symmetric access control mechanism for the SPA';
COMMENT ON COLUMN legitimization_measures.start_time
IS 'Time when the measure was triggered (by decision or rule)';
+ -- FIXME: LegitimizationMeasures is *bad* here, as we only have the KycRule; the specific measure may
+ -- not yet have been selected at the time of the trigger!
COMMENT ON COLUMN legitimization_measures.jmeasures
IS 'JSON object of type LegitimizationMeasures with KYC/AML measures for the account encoded';
COMMENT ON COLUMN legitimization_measures.display_priority
@@ -1885,86 +1412,13 @@ on GET ``/deposits/`` with the respective legitimization requirement row.
The ``jmeasures`` JSON in the ``legitimization_measures``
-table has is of type `LegitimizationMeasures`:
-
-.. ts:def:: LegitimizationMeasures
-
- interface LegitimizationMeasures {
-
- // Array of legitimization measures that
- // are to be applied.
- measures: MeasureInformation[];
-
- // True if the client is expected to eventually satisfy all requirements.
- // Default (if missing) is false.
- is_and_combinator?: boolean;
- }
-
+table is of type `LegitimizationMeasures`:
The ``jnew_rules`` JSON in the ``legitimization_outcomes``
-table has is of type `LegitimizationRuleSet`:
-
-.. ts:def:: LegitimizationRuleSet
-
- 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
- // ``successor_measure`` may refer to.
- custom_measures: { "$measure_name" : MeasureInformation; };
- }
-
-
-The ``jproperties`` JSON in the ``legitimization_outcomes`` table has is of
-type `AccountProperties`. 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.
-
-.. ts:def:: AccountProperties
-
- 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;
-
- }
+table is of type `LegitimizationRuleSet`.
+The ``jproperties`` JSON in the ``legitimization_outcomes`` table is of
+type `AccountProperties`.
KYC forms
diff --git a/frags/installing-ubuntu.rst b/frags/installing-ubuntu.rst
index f31b4ec6..89ca4dc9 100644
--- a/frags/installing-ubuntu.rst
+++ b/frags/installing-ubuntu.rst
@@ -17,7 +17,11 @@ For Ubuntu Mantic use this instead:
deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/ubuntu/ mantic taler-mantic
-The last line is crucial, as it adds the GNU Taler packages.
+For Ubuntu Noble use this instead:
+
+.. code-block::
+
+ deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/ubuntu/ noble taler-noble
Next, you must import the Taler Systems SA public package signing key
into your keyring and update the package lists:
diff --git a/libeufin/index.rst b/libeufin/index.rst
index c77255b0..4fd7668c 100644
--- a/libeufin/index.rst
+++ b/libeufin/index.rst
@@ -31,4 +31,5 @@ LibEuFin is a project providing free software tooling for European FinTech.
bank-manual
regional-automated-manual
regional-custom-manual
+ regional-manual-use
setup-ebics-at-postfinance
diff --git a/libeufin/regional-automated-manual.rst b/libeufin/regional-automated-manual.rst
index f416d1b9..39dfd3f6 100644
--- a/libeufin/regional-automated-manual.rst
+++ b/libeufin/regional-automated-manual.rst
@@ -241,7 +241,6 @@ manual setup and in the the manpage of ``taler-exchange-offline``.
.. include:: ../frags/regional-system-on.rst
.. include:: ../frags/deploying-tos.rst
-.. include:: ../frags/regional-manual-use.rst
Installing Updates
diff --git a/libeufin/regional-custom-manual.rst b/libeufin/regional-custom-manual.rst
index 7da39c96..4a347791 100644
--- a/libeufin/regional-custom-manual.rst
+++ b/libeufin/regional-custom-manual.rst
@@ -141,7 +141,6 @@ account with "CHF".
.. include:: ../frags/regional-system-on.rst
.. include:: ../frags/deploying-tos.rst
-.. include:: ../frags/regional-manual-use.rst
Maintenance
diff --git a/frags/regional-manual-use.rst b/libeufin/regional-manual-use.rst
index 7566d622..ff9f38f8 100644
--- a/frags/regional-manual-use.rst
+++ b/libeufin/regional-manual-use.rst
@@ -1,3 +1,22 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2024 Taler Systems SA
+
+ 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 2.1, or (at your option) any later version.
+
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Florian Dold
+ @author Marcello Stanisci
+ @author Christian Grothoff
+
.. _regional-use:
Using the Regional Currency
diff --git a/manpages/libeufin-nexus.1.rst b/manpages/libeufin-nexus.1.rst
index a0ed99ff..5eb42cab 100644
--- a/manpages/libeufin-nexus.1.rst
+++ b/manpages/libeufin-nexus.1.rst
@@ -93,7 +93,7 @@ Its options are as follows:
Configure logging to use LOGLEVEL.
Uploaded documents will be stored *before* being submitted to the bank. This directory would contain several directories, each named after the ``YYYY-MM-DD/submit`` format. The pain.001 file would then be named in the following schema: ``$microseconds_pain.001.xml``.
**--transient**
- This flag, enabled by default, causes the command to check the database and submit only once, and then return.
+ This flag causes the command to check the database and submit only once, and then return.
ebics-fetch
@@ -105,6 +105,8 @@ The files type can be given as an argument to select what will be fetched. If no
* ``acknowledgement``: EBICS acknowledgement, retrieves the status of EBICS orders.
* ``status``: Payment status, retrieves status of pending debits.
+* ``report``: Account intraday reports, retrieves the history of confirmed debits and credits.
+* ``statement``: Account statements, retrieves the history of confirmed debits and credits.
* ``notification``: Debit & credit notifications, retrieves the history of confirmed debits and credits.
**-h** \| **--help**
@@ -117,10 +119,26 @@ The files type can be given as an argument to select what will be fetched. If no
Log EBICS content at SAVEDIR.
Downloaded documents will be stored *before* being ingested in the database. This directory would contain several directories, each named after the ``YYYY-MM-DD/fetch`` format. The stored files would then be named after the following schema: ``$microseconds_$filename``. Exception to this naming scheme are the HAC responses, since they do not get any filename assigned by the ZIP archive (they are sent unzipped). Their naming scheme is: ``$microseconds_HAC_response.pain.002.xml``.
**--transient**
- This flag, enabled by default, causes the command to perform one download and return.
+ This flag causes the command to perform one download and return.
**--pinned-start**
Only supported in --transient mode, this option lets specify the earliest timestamp of the downloaded documents. The latest timestamp is always the current time.
+serve
+-----
+
+This command starts the HTTP server.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+**--check**
+ This flag causes the command to check whether an API is in use (if it's useful to start the HTTP server) and to output 0 if at least one API is enabled, otherwise 1.
+
initiate-payment
----------------
diff --git a/manpages/libeufin-nexus.conf.5.rst b/manpages/libeufin-nexus.conf.5.rst
index 9100f8fe..8aabe883 100644
--- a/manpages/libeufin-nexus.conf.5.rst
+++ b/manpages/libeufin-nexus.conf.5.rst
@@ -116,8 +116,8 @@ HOST_BASE_URL
BANK_DIALECT
Name of the following combination: EBICS version and ISO20022 recommendations
- that Nexus would honor in the communication with the bank. Currently only the
- 'postfinance' value is supported.
+ that Nexus would honor in the communication with the bank. Currently only the
+ ``postfinance`` or ``gls`` value is supported.
HOST_ID
EBICS specific: name of the EBICS host
@@ -167,6 +167,60 @@ FREQUENCY
IGNORE_TRANSACTIONS_BEFORE
Ignore all transactions before a certain YYYY-MM-DD date, useful when you want to use an existing account with old transactions that should not be bounced.
+HTTP SERVER OPTIONS
+-------------------
+
+The following configuration value(s) belong to the “[nexus-httpd]” section.
+
+SERVE
+ This can either be ``tcp`` or ``unix``.
+
+PORT
+ Port on which the HTTP server listens, e.g. 9967.
+ Only used if ``SERVE`` is ``tcp``.
+
+BIND_TO
+ Which IP address should we bind to? E.g. ``127.0.0.1`` or ``::1``for loopback. Can also be given as a hostname.
+ Only used if ``SERVE`` is ``tcp``.
+
+UNIXPATH
+ Which unix domain path should we bind to?
+ Only used if ``SERVE`` is ``unix``.
+
+UNIXPATH_MODE
+ What should be the file access permissions for ``UNIXPATH``?
+ Only used if ``SERVE`` is ``unix``.
+
+HTTP WIRE GATEWAY API OPTIONS
+-----------------------------
+
+The following configuration value(s) belong to the “[nexus-httpd-wire-gateway-api]” section.
+
+ENABLED
+ Whether to serve the Wire Gateway API.
+
+AUTH_METHOD
+ How to authenticate this API. This can either be ``none`` or ``bearer-token``.
+
+AUTH_BEARER_TOKEN
+ The expected token.
+ Only used if ``AUTH_METHOD`` is ``bearer-token``.
+
+HTTP REVENUE API OPTIONS
+------------------------
+
+The following configuration value(s) belong to the “[nexus-httpd-revenue-api]” section.
+
+ENABLED
+ Whether to serve the Revenue API.
+
+AUTH_METHOD
+ How to authenticate this API. This can either be ``none`` or ``bearer-token``.
+
+AUTH_BEARER_TOKEN
+ The expected token.
+ Only used if ``AUTH_METHOD`` is ``bearer-token``.
+
DATABASE OPTIONS
----------------
diff --git a/manpages/taler.conf.5.rst b/manpages/taler.conf.5.rst
index 3074f68b..ee5d3cd1 100644
--- a/manpages/taler.conf.5.rst
+++ b/manpages/taler.conf.5.rst
@@ -254,19 +254,29 @@ PRIVACY_ETAG
EXCHANGE KYC PROVIDER OPTIONS
-----------------------------
-The following options must be in the section "[kyc-provider-XXX]" sections.
-
-COST
- Relative cost of the KYC provider, non-negative number.
+The following options must be in the section "[kyc-provider-$PROVIDER_NAME]" sections.
LOGIC
API type of the KYC provider.
-USER_TYPE
- Type of user this provider is for, either INDIVIDUAL or BUSINESS.
+CONVERTER
+ 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).
+
+COST
+ Optional cost, useful if clients want to voluntarily
+ trigger authentication procedures for attestation.
-PROVIDED_CHECKS
- List of checks performed by this provider. Space-separated names of checks, must match check names in legitimization rules.
+Additional logic-specific options may be given in the
+section.
EXCHANGE KYC OAUTH2 OPTIONS
@@ -362,6 +372,169 @@ WEBHOOK_AUTH_TOKEN
Authentication token Persona must supply to our webhook. This is an optional setting.
+EXCHANGE KYC CHECK OPTIONS
+--------------------------
+
+The following options must be in "[kyc-check-$CHECK_NAME]" sections.
+
+TYPE
+ 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
+
+VOLUNTARY
+ 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.
+
+PROVIDER_ID
+ Provider id, present only if type is LINK.
+ Refers to a ``kyc-provider-$PROVIDER_ID`` section.
+
+FORM_NAME
+ 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.
+ The list of possible FORM names is fixed in the SPA
+ for a particular exchange release.
+
+DESCRIPTION
+ Descriptions to use in the SPA to display the check.
+
+DESCRIPTION_I18N
+ JSON with internationalized descriptions to use
+ in the SPA to display the check.
+
+REQUIRES
+ ';'-separated list of fields that the CONTEXT must
+ provide 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.
+
+OUTPUTS = business_name street city country registration
+ Description of the outputs provided by the check.
+ Basically, the check's output is expected to
+ provide the following fields as attribute inputs into
+ a subsequent AML program.
+ Only given for type FORM; INFO never has any outputs,
+ and for type LINK we can obtain the same information
+ from the CONVERTER via ``--list-outputs``.
+
+FALLBACK
+ Name of an **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. The fallback measure
+ context always includes the reasons for the
+ failure.
+
+EXCHANGE KYC RULES
+------------------
+
+The following options must be in "[kyc-rule-$RULE_NAME]" sections.
+
+OPERATION_TYPE = WITHDRAW
+ Operation that triggers this rule.
+ Must be one of WITHDRAW, DEPOSIT, P2P-RECEIVE
+ or WALLET-BALANCE.
+
+NEXT_MEASURES
+ Space-separated list of next measures to be performed.
+ The SPA should 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 name "verboten" is used if the
+ specified threshold may never be crossed
+ (under this set of rules).
+
+IS_AND_COMBINATOR
+ "YES" if all NEXT_MEASURES will eventually need
+ to be satisfied, "NO" 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". YES for "and".
+
+EXPOSED
+ 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.
+
+THRESHOLD
+ Threshold amount above which the rule is
+ triggered. The total must be exceeded in the given
+ timeframe.
+
+TIMEFRAME
+ Timeframe over which the amount to be compared to
+ the THRESHOLD is calculated (for example, "30 days").
+ Ignored for WALLET-BALANCE. Can be 'forever'.
+
+ENABLED = NO
+ Set to YES to enable the rule (default is NO).
+
+
+EXCHANGE AML PROGRAMS
+---------------------
+
+The following options must be in "[aml-program-$PROG_NAME]" sections.
+
+COMMAND
+ Name of the program to run. Must match a binary
+ on the local machine where the exchange is running.
+
+DESCRIPTION
+ Human-readable description of what this
+ AML helper program will do. Used to show
+ to the AML staff.
+
+ENABLED
+ True if this AML program is enabled (and thus can be
+ used in measures and exposed to AML staff).
+ Optional, default is NO.
+
+FALLBACK
+ Name of an **original** measure to take if COMMAND fails
+ Usually points to a measure that asks AML staff
+ to contact the systems administrator. The fallback measure
+ context always includes the reasons for the
+ failure.
+
+EXCHANGE KYC MEASURES
+---------------------
+
+The following options must be in "[kyc-measure-$MEASURE_NAME]" sections. These sections define the **original** measures.
+
+CHECK_NAME
+ Name of a possible check for this measure. Optional.
+ If not given, PROGRAM should be run immediately
+ (on an empty set of attributes).
+
+CONTEXT = {"choices":["individual","business"]}
+ Context for the check. The context can be
+ just an empty JSON object if there is none.
+
+PROGRAM
+ Program to run on the context and check data to
+ determine the outcome and next measure.
+ Refers to a ``[aml-program-$PROG_NAME]`` section name.
+
+
EXCHANGE EXTENSIONS OPTIONS
---------------------------
diff --git a/python-guidelines.rst b/orphaned/python-guidelines.rst
index 8a644ced..8a644ced 100644
--- a/python-guidelines.rst
+++ b/orphaned/python-guidelines.rst
diff --git a/checklists/qa-0.9.4.rst b/orphaned/qa-0.9.4.rst
index 77e51081..77e51081 100644
--- a/checklists/qa-0.9.4.rst
+++ b/orphaned/qa-0.9.4.rst
diff --git a/taler-developer-manual.rst b/taler-developer-manual.rst
index 3035e55d..c225e747 100644
--- a/taler-developer-manual.rst
+++ b/taler-developer-manual.rst
@@ -368,12 +368,6 @@ you can add the nightly package sources.
$ wget -O - https://taler.net/taler-systems-nightly.gpg.key | apt-key add -
-Language-Specific Guidelines
-============================
-
-* :doc:`Python Guidelines <python-guidelines>`
-
-
Taler Deployment on gv.taler.net
================================
@@ -648,7 +642,7 @@ outside of this versioning. All tables of a GNU Taler component should live in
QA Plans
========
-.. include:: checklists/qa-0.9.4.rst
+.. include:: checklists/qa-0.10.rst
Releases
diff --git a/taler-exchange-manual.rst b/taler-exchange-manual.rst
index 91865f24..069b256c 100644
--- a/taler-exchange-manual.rst
+++ b/taler-exchange-manual.rst
@@ -1023,6 +1023,20 @@ Taler KYC Terminology
*cost*. Interaction with a provider is performed by provider-specific
*logic*.
+Configuration of possible KYC/AML checks
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The configuration specifies a set of possible KYC checks offered by external
+providers. The names of the configuration sections must being with
+``kyc-check-`` followed by an arbitrary ``$CHECK_NAME``.
+
+The list of possible FORM names is fixed in the SPA
+for a particular exchange release.
+
+The outcome of *any* check should always be uploaded encrypted into the
+``kyc_attributes`` table. It MUST include an ``expiration_time``.
+
+
KYC Configuration Options
-------------------------
@@ -1724,6 +1738,155 @@ from ``https://git.taler.net/wallet-core.git/``, compile and copy the file
from the ``dist/prod``.
+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 of type
+ `AmlProgramInput` into a JSON object of
+ type `AmlOutcome`.
+ This is the default behavior if no command-line switches
+ are provided.
+
+.. 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.
+ aml_history: AmlDecisionDetail[];
+
+ // JSON array with the results of historic
+ // KYC data about the account.
+ kyc_history: KycDetail[];
+
+ }
+
+.. ts:def:: AmlOutcome
+
+ 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;
+
+ }
+
+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
+
+ [aml-program-$PROG_NAME]
+
+ # Program to run.
+ COMMAND = taler-helper-aml-pep
+
+ # 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
+ # to contact the systems administrator. The fallback measure
+ # context always includes the reasons for the
+ # failure.
+ FALLBACK = MEASURE_NAME
+
+AML Measures
+------------
+
+The exchange configuration specifies a set of
+**original** *measures* one per configuration section:
+
+.. code-block:: ini
+
+ [kyc-measure-$MEASURE_NAME]
+
+ # Possible check for this measure. Optional.
+ # If not given, PROGRAM should be run immediately
+ # (on an empty set of attributes).
+ CHECK_NAME = IB_FORM
+
+ # Context for the check. The context can be
+ # just an empty JSON object if there is none.
+ CONTEXT = {"choices":["individual","business"]}
+
+ # Program to run on the context and check data to
+ # 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.
+
+.. 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.
+
+
+
Setup Linting
=============
@@ -1902,6 +2065,22 @@ The database scheme used by the exchange looks as follows:
.. image:: images/exchange-db.png
+The ``jmeasures`` JSON in the ``legitimization_measures``
+table is of type `LegitimizationMeasures`:
+
+.. ts:def:: LegitimizationMeasures
+
+ interface LegitimizationMeasures {
+
+ // Array of legitimization measures that
+ // are to be applied.
+ measures: MeasureInformation[];
+
+ // True if the client is expected to eventually satisfy all requirements.
+ // Default (if missing) is false.
+ is_and_combinator?: boolean;
+ }
+
.. _Database-upgrades: