summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Häberli <haebu@rubigen.ch>2024-04-17 11:00:17 +0200
committerJoel Häberli <haebu@rubigen.ch>2024-04-17 11:00:17 +0200
commit2b22f8b1c3881aded929c640705d7605af2706b8 (patch)
tree065387fba47a5ec9951c3bafe6b5004b63316d95
parent3b11d630bc7a6ab9d5ba3bdcc401e77f3c821627 (diff)
parentfdcd1205c73a4600e23efcd56edcdd6e1c5a39ec (diff)
downloaddocs-2b22f8b1c3881aded929c640705d7605af2706b8.tar.gz
docs-2b22f8b1c3881aded929c640705d7605af2706b8.tar.bz2
docs-2b22f8b1c3881aded929c640705d7605af2706b8.zip
Merge remote-tracking branch 'refs/remotes/origin/master'
-rw-r--r--conf.py11
-rw-r--r--core/api-challenger.rst194
-rw-r--r--core/api-exchange.rst2
-rw-r--r--core/api-merchant.rst19
-rw-r--r--design-documents/023-taler-kyc.rst1344
-rw-r--r--design-documents/053-wallet-ui.rst27
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-01.pngbin0 -> 199631 bytes
l---------design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-latest.png1
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/11-balances-list-01.pngbin0 -> 320043 bytes
l---------design-documents/wallet-screenshots/ios-wallet/11-balances-list-latest.png1
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-sheet130-withdraw-confirm.pngbin193455 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-sheet130-withdraw.pngbin237544 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-sheet133-withdraw-confirm-bank.pngbin231969 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-view22-balances.pngbin234937 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-confirm.pngbin357675 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-confirmed.pngbin357108 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-register.pngbin338618 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-send-money.pngbin464966 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-withdraw.pngbin505046 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet130-withdraw-confirm.pngbin202047 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet130-withdraw.pngbin246405 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet131-tos.pngbin317496 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet133-withdraw-confirm-bank.pngbin230382 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-view10-empty-wallet.pngbin169741 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-view22-balances.pngbin239045 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-amount.pngbin173529 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-wireTransfer-CHF-1.pngbin292949 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-wireTransfer-CHF-2.pngbin407510 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-wireTransfer-CHF-3.pngbin331196 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-amount.pngbin215793 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-amount2.pngbin214738 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-tos.pngbin116707 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-CHF.pngbin304402 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-CHF2.pngbin420238 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-NETZ.pngbin309949 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-NETZ2.pngbin413992 -> 0 bytes
-rw-r--r--design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-withdraw-tos.pngbin170387 -> 0 bytes
-rw-r--r--frags/common-conf-syntax.rst16
-rw-r--r--frags/configuration-format.rst13
-rw-r--r--frags/legal.rst32
-rw-r--r--manpages/libeufin-cli.1.rst1006
-rw-r--r--manpages/libeufin-sandbox.1.rst227
-rw-r--r--taler-challenger-manual.rst231
-rw-r--r--taler-exchange-manual.rst6
-rw-r--r--taler-merchant-manual.rst4
45 files changed, 1444 insertions, 1690 deletions
diff --git a/conf.py b/conf.py
index db8a4069..43e6ae59 100644
--- a/conf.py
+++ b/conf.py
@@ -85,9 +85,9 @@ copyright = "2014-2024 Taler Systems SA (GPLv3+ or GFDL 1.3+)"
# built documents.
#
# The short X.Y version.
-version = "0.9"
+version = "0.10"
# The full version, including alpha/beta/rc tags.
-release = "0.9.4"
+release = "0.10.0"
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -729,13 +729,6 @@ man_pages = [
1,
),
(
- "manpages/libeufin-sandbox.1",
- "libeufin-sandbox",
- "simulate core banking system with EBICS access to bank accounts",
- "GNU Taler contributors",
- 1,
- ),
- (
"manpages/libeufin-nexus.1",
"libeufin-nexus",
"service to interface to various bank access APIs",
diff --git a/core/api-challenger.rst b/core/api-challenger.rst
index 914d8d01..f8631977 100644
--- a/core/api-challenger.rst
+++ b/core/api-challenger.rst
@@ -1,6 +1,6 @@
..
This file is part of GNU TALER.
- Copyright (C) 2023 Taler Systems SA
+ Copyright (C) 2023, 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
@@ -29,19 +29,19 @@ The high-level flow is that an OAuth 2.0 client is first registered with the
challenger service (via command-line). Using the command-line tool will print
the resulting client ID to the console.
- .. note::
+.. note::
- The current service mandates that redirection URIs
- start with "http://" or "https://". See issue #7838
- for what should be done to lift this restriction.
+ The current service mandates that redirection URIs
+ start with "http://" or "https://". See issue #7838
+ for what should be done to lift this restriction.
- .. note::
+.. note::
- Right now, registration of a unique redirection URI is *mandatory* for
- each client. If multiple redirection URIs are needed, it is suggested to
- just register additional clients. (While OAuth 2.0 would support not
- registering fixed redirection URIs with a client, this is not recommended
- as it would create an open redirector.)
+ Right now, registration of a unique redirection URI is *mandatory* for
+ each client. If multiple redirection URIs are needed, it is suggested to
+ just register additional clients. (While OAuth 2.0 would support not
+ registering fixed redirection URIs with a client, this is not recommended
+ as it would create an open redirector.)
Once a client is registered, that client can use the challenger service when
it needs a user to prove that the user is able to receive messages at a
@@ -61,13 +61,13 @@ of the challenger service, adding its ``state``, ``client_id`` and
redirect URI registered with the client. From this endpoint, the challenger
service will return a Web page asking the user to provide its address.
- .. note::
+.. note::
- Challenger is a bit unusual in that the ``$NONCE`` in the endpoint URL
- makes the authorization endpoint URL (deliberately) unpredictable, while
- for many other OAuth 2.0 APIs this endpoint is static. However, this is
- compliant with OAuth 2.0 as determining the authorization URL is left out
- of the scope of the standard.
+ Challenger is a bit unusual in that the ``$NONCE`` in the endpoint URL
+ makes the authorization endpoint URL (deliberately) unpredictable, while
+ for many other OAuth 2.0 APIs this endpoint is static. However, this is
+ compliant with OAuth 2.0 as determining the authorization URL is left out
+ of the scope of the standard.
When the user has filled in the form with their address, it will be submitted
to the ``/challenge/$NONCE`` endpoint and the challenger service will send a
@@ -99,7 +99,7 @@ Receiving Configuration
.. http:get:: /config
Obtain the key configuration settings of the storage service.
- This specification corresponds to ``current`` protocol being version **0**.
+ This specification corresponds to ``current`` protocol being version **1**.
**Response:**
@@ -168,6 +168,16 @@ Login
endpoint is used by the user-agent. It will return a form to enter the
address.
+ The NONCE is a unique value identifying the challenge, should be shown to
+ the user so that they can recognize it when they receive the TAN code.
+
+ This endpoint typically also supports requests with the "Accept" header
+ requesting "text/html". In this case, an HTML response using the template
+ :ref:`enter-$ADDRESS_TYPE-form <challenger_enter-address_type-form>` is
+ returned. If the backend installation does not include the required HTML
+ templates, a 406 status code is returned.
+
+
**Request:**
:query response_type: Must be ``code``
@@ -179,10 +189,55 @@ Login
**Response:**
:http:statuscode:`200 OK`:
- The body contains a form to be submitted by the user-agent.
+ If the request ask for application/json then the response is
+ a `ChallengeStatus`. Since protocol **v1**.
+ Otherwise, the body contains a form to be submitted by the user-agent
+ using the template :ref:`enter-$ADDRESS_TYPE-form <challenger_enter-address_type-form>`.
The form will ask the user to specify their address.
+ :http:statuscode:`400 Bad Request`:
+ The request does not follow the spec.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`invalid-request <challenger_invalid-request>`.
:http:statuscode:`404 Not found`:
- The backup service is unaware of a matching $NONCE.
+ The service is unaware of a matching challenge.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`validation-unknown <challenger_validation-unknown>`.
+ :http:statuscode:`406 Not Acceptable`:
+ The client ask for "text/html" and the backend installation does
+ not include the required HTML templates.
+ :http:statuscode:`500 Internal Server Error`:
+ Server is not able to respond due to internal problems.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`internal-error <challenger_internal-error>`.
+
+ .. ts:def:: ChallengeStatus
+
+ interface ChallengeStatus {
+ // Object; map of keys (names of the fields of the address
+ // to be entered by the user) to objects with a "regex" (string)
+ // containing an extended Posix regular expression for allowed
+ // address field values, and a "hint"/"hint_i18n" giving a
+ // human-readable explanation to display if the value entered
+ // by the user does not match the regex. Keys that are not mapped
+ // to such an object have no restriction on the value provided by
+ // the user. See "ADDRESS_RESTRICTIONS" in the challenger configuration.
+ restrictions: Object;
+
+ // indicates if the given address cannot be changed anymore, the
+ // form should be read-only if set to true.
+ fix_address: boolean;
+
+ // form values from the previous submission if available, details depend
+ // on the ``ADDRESS_TYPE``, should be used to pre-populate the form
+ last_address: Object;
+
+ // number of times the address can still be changed, may or may not be
+ // shown to the user
+ changes_left: Integer;
+ }
.. _challenger-challenge:
@@ -204,15 +259,57 @@ Challenge
**Response:**
:http:statuscode:`200 OK`:
- The body contains a form asking for the answer to
- the challenge to be entered by the user.
- :http:statuscode:`404 Not found`:
- The challenger service is unaware of a matching nonce.
+ If the request ask for application/json the response is `ChallengeCreateResponse`. Since protocol **v1**.
+ Otherwise, the body contains a form asking for the answer to
+ the challenge to be entered by the user using the
+ template :ref:`enter-tan-form <challenger_enter-tan-form>`.
+ :http:statuscode:`400 Bad Request`:
+ The request does not follow the spec.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`invalid-request <challenger_invalid-request>`.
+ :http:statuscode:`404 Not Found`:
+ The service is unaware of a matching challenge.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`validation-unknown <challenger_validation-unknown>`.
+ :http:statuscode:`406 Not Acceptable`:
+ The client ask for "text/html" and the backend installation does
+ not include the required HTML templates.
:http:statuscode:`429 Too Many Requests`:
There have been too many attempts to request challenge
transmissions for this $NONCE. The user-agent should
wait and (eventually) request a fresh nonce to be set
up by the client.
+ :http:statuscode:`500 Internal Server Error`:
+ Server is not able to respond due to internal problems.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`internal-error <challenger_internal-error>`.
+
+ .. ts:def:: ChallengeCreateResponse
+
+ interface ChallengeCreateResponse {
+
+ // how many more attempts are allowed, might be shown to the user,
+ // highlighting might be appropriate for low values such as 1 or 2 (the
+ // form will never be used if the value is zero)
+ attempts_left: Integer;
+
+ // the address that is being validated, might be shown or not
+ address: Object;
+
+ // true if we just retransmitted the challenge, false if we sent a
+ // challenge recently and thus refused to transmit it again this time;
+ // might make a useful hint to the user
+ transmitted: boolean;
+
+ // timestamp explaining when we would re-transmit the challenge the next
+ // time (at the earliest) if requested by the user
+ next_tx_time: String;
+
+ }
+
.. _challenger-solve:
@@ -239,16 +336,61 @@ Solve
by the client (during registration and again upon ``/authorize``),
plus a ``code`` argument with the authorization code, and the
``state`` argument from the ``/authorize`` endpoint.
+ :http:statuscode:`400 Bad Request`:
+ The request does not follow the spec.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`invalid-request <challenger_invalid-request>`.
:http:statuscode:`403 Forbidden`:
- The solution of the user to the challenge is invalid.
+ If the request ask for application/json the response is `InvalidPinResponse`. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`invalid-pin <challenger_invalid-pin>`.
:http:statuscode:`404 Not found`:
The service is unaware of a matching challenge.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`validation-unknown <challenger_validation-unknown>`.
:http:statuscode:`429 Too Many Requests`:
There have been too many attempts to solve the challenge
for this address (and $NONCE). The user-agent should
either try a different address (or wait and (eventually)
request a fresh nonce to be set up by the client).
-
+ :http:statuscode:`500 Internal Server Error`:
+ Server is not able to respond due to internal problems.
+ If the request ask for application/json the response will include error
+ code, hint and detail. Since protocol **v1**.
+ Otherwise, the body contains information using the template :ref:`internal-error <challenger_internal-error>`.
+
+ .. ts:def:: InvalidPinResponse
+
+ interface InvalidPinResponse {
+ // numeric Taler error code, should be shown to indicate the error
+ // compactly for reporting to developers
+ ec: Integer;
+
+ // human-readable Taler error code, should be shown for the user to
+ // understand the error
+ hint: String;
+
+ // how many times is the user still allowed to change the address;
+ // if 0, the user should not be shown a link to jump to the
+ // address entry form
+ addresses_left: Integer;
+
+ // how many times might the PIN still be retransmitted
+ pin_transmissions_left: Integer;
+
+ // how many times might the user still try entering the PIN code
+ auth_attempts_left: Integer;
+
+ // if true, the PIN was not even evaluated as the user previously
+ // exhausted the number of attempts
+ exhausted: boolean;
+
+ // if true, the PIN was not even evaluated as no challenge was ever
+ // issued (the user must have skipped the step of providing their
+ // address first!)
+ no_challenge: boolean;
+ }
.. _challenger-auth:
diff --git a/core/api-exchange.rst b/core/api-exchange.rst
index d41372d8..4c5be000 100644
--- a/core/api-exchange.rst
+++ b/core/api-exchange.rst
@@ -1418,6 +1418,7 @@ and freeze or unfreeze accounts suspected of money laundering.
// What was the justification given?
justification: string;
+ // FIXME: review!
// What is the new AML state.
new_state: Integer;
@@ -1438,6 +1439,7 @@ and freeze or unfreeze accounts suspected of money laundering.
// Name of the configuration section that specifies the provider
// which was used to collect the KYC details
+ // FIXME: review!
provider_section: string;
// The collected KYC data. NULL if the attribute data could not
diff --git a/core/api-merchant.rst b/core/api-merchant.rst
index 3eb92c22..4d74d4b2 100644
--- a/core/api-merchant.rst
+++ b/core/api-merchant.rst
@@ -350,15 +350,17 @@ Making the payment
// The coins used to make the payment.
coins: CoinPaySig[];
- // Index of the chosen sub-contract.
+ // Index of the selected choice within the ``choices`` array of
+ // the contract terms.
// @since protocol **vSUBSCRIBE**
choice_index?: Integer;
// Input tokens required by choice indicated by ``choice_index``.
// @since protocol **vSUBSCRIBE**
- tokens: TokenPaySig[];
+ tokens: TokenUseSig[];
- // Array of blinded output tokens to be (blindly) signed by the merchant.
+ // Array of output tokens to be (blindly) signed by the merchant.
+ // Output tokens specified in choice indicated by ``choice_index``.
// @since protocol **vSUBSCRIBE**
tokens_evs: TokenEnvelope[];
@@ -412,9 +414,9 @@ Making the payment
h_age_commitment?: AgeCommitmentHash;
}
- .. ts:def:: TokenPaySig
+ .. ts:def:: TokenUseSig
- interface TokenPaySig {
+ interface TokenUseSig {
// Signature on ``TALER_DepositRequestPS`` with the public key of the
// token being provisioned to the merchant.
@@ -2178,7 +2180,7 @@ protocol **vSUBSCRIBE**.
inputs: OrderInput[];
// Outputs provided by the merchant, if this choice is selected.
- outputs: ContractOutput[];
+ outputs: OrderOutput[];
}
.. ts:def:: OrderInput
@@ -2439,6 +2441,11 @@ Inspecting orders
// Contract terms.
contract_terms: ContractTerms;
+ // Index of the selected choice within the ``choices`` array of
+ // ``contract terms``.
+ // @since protocol **vSUBSCRIBE**
+ choice_index?: Integer;
+
// If the order is paid, set to the last time when a payment
// was made to pay for this order. Since **v14**.
last_payment: Timestamp;
diff --git a/design-documents/023-taler-kyc.rst b/design-documents/023-taler-kyc.rst
index 01e3ec7f..1eb0669e 100644
--- a/design-documents/023-taler-kyc.rst
+++ b/design-documents/023-taler-kyc.rst
@@ -4,21 +4,20 @@ DD 23: Taler KYC
Summary
=======
-This document discusses the Know-your-customer (KYC) processes supported by Taler.
+This document discusses the Know-your-customer (KYC) and Anti-Money Laundering
+(AML) processes supported by Taler.
Motivation
==========
-To legally operate, Taler has to comply with KYC regulation that requires
+To legally operate, Taler has to comply with KYC/AML regulation that requires
banks to identify parties involved in transactions at certain points.
Requirements
============
-The solution should support fees to be paid by the user for the KYC process (#7365).
-
Taler needs to take *measures* based on the following primary *triggers*:
* Customer withdraws money over a monthly threshold
@@ -48,8 +47,15 @@ Taler needs to take *measures* based on the following primary *triggers*:
customer records against the list
-For the different *measures*, there are various different possible KYC/AML *checks*
-that could happen:
+Process requirements
+^^^^^^^^^^^^^^^^^^^^
+
+The key consideration here is *plausibilization*: staff needs to
+check that the client-provided information is plausible. As this
+is highly case-dependent, this cannot be automated.
+
+For the different *measures*, there are various different possible KYC/AML
+*checks* that could happen:
* In-person validation by AML staff
* Various forms to be filled by AML staff
@@ -78,13 +84,45 @@ There are also various *outcomes*:
* held, AML staff reviewing evidence for plausibilization (new measure)
* automatically frozen until certain day (due to sanctions)
* institutionally frozen until certain day (due to order by state authority)
+* operation is categorically not allowed (at least above certain limits)
+
+Outcomes may also be (partially) public, that is exposed to the client. For
+example, we may want to tell a wallet that it has hit a hard withdraw limit,
+but might succeed at withdrawing a smaller amount.
+
+The outcome of a *check* can set new rules or trigger another *measure* (the
+latter is conditional on reaching the expiration time of the outcome).
+
+As a result, we largely end up in a large state machine where the AML staff has
+serious flexibiltiy while the user needs guidance as to the possible next moves
+and/or to the current state of their account (where some information must not be
+disclosed).
+
-The outcome of a *check* can trigger further *measures* (including
-expiration of the outcome state).
+Documentation requirements
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+For each account we must:
+
+* define risk-profile (902.4, 905.1)
+* document the specific setup, likely not just the INI file
+* should have some key AMLA file attributes, such as:
+
+ * File opened, file closed (keep data for X years afterwards!)
+ * low-risk or high-risk business relationship
+ * PEP status
+ * business domain
+ * authority notification dates (possibly multiple) with
+ voluntary or mandatory notification classification
Finally, we need to produce statistics:
+* There must be a page with an overview of AMLA files with opening
+ and closing dates and an easy way to determine for any day the
+ number of open AMLA files
+* Technically, we also need a list of at-risk transactions and of
+ frozen transactions, but given that we can really only freeze
+ on an account-basis, I think there is nothing to do here
* number of incidents reported (voluntarily, required)
* number of business relationships at any point in time
* number of risky business relationships (PEP, etc.)
@@ -94,18 +132,24 @@ Finally, we need to produce statistics:
For this high-level monitoring, we need certain designated critical events to
be tracked in the system statistics:
- * account opened
- * set to high risk
- * set to low risk
- * suspicious activity report filed with authority
- * account frozen
- * account unfrozen
- * account closed
+* account opened
+* set to high risk
+* set to low risk
+* suspicious activity report filed with authority
+* account frozen
+* account unfrozen
+* account closed
-As a result, we largely end up in a large state machine where the AML staff has
-serious flexibiltiy while the user needs guidance as to the possible next moves
-and/or to the current state of their account (where some information must not be
-disclosed).
+
+Further considerations
+^^^^^^^^^^^^^^^^^^^^^^
+
+On top of all of this, we need to plan some *diagnostics* to determine when
+components fail (such as scripts or external services providing malformed
+results).
+
+Optionally, in the future, the solution should support fees to be paid by the
+user for *voluntary* KYC processes related to attestation (#7365).
Proposed Solution
@@ -116,43 +160,41 @@ For the different *measures*, we define:
* Who has to do something (AML staff, user, nobody)
* Contextual input data to be provided (with templating, e.g. amount set dynamically based on the *trigger*)
-* A *check* to be performed
+* A *check* to be performed (user-interactive or staff-interactive)
+* Another *measure* to take on failure of a user-interactive check
* A *program* that uses data from the *check* as well as *context* data
to determine an *outcome* which is the specific operational state
(normal, held on staff, held on user, frozen, etc.) the account is to transition to
* What information about the state to show to the user (normal, information required, pending, etc.)
-* For user-interactive checks:
-
- * Web page template with instructions to render (with either a form to fill or links to external checks);
- here the context could provide an array of choices!
- * Possibly an external check to set up (if any); for cost-reasons, we should only do one at a time,
- and probably should then always redirect the browser to that check.
- * A *measure* to take on failure of the external check
+For the user-interactive checks we need a SPA (for KYC) that is given:
-* For (AML) staff-interactive checks:
+* instructions to render (with either a form to fill or links to external checks);
+ here the context could provide an array of choices!
+* possibly an external check that was set up (if any); for cost-reasons, we should only do one at a time,
+ and probably should then always redirect the browser to that check.
- * UI to file forms and upload documentation (without state transition)
- * UI to decide on next measure (providing context); here, the exchange needs
- to expose the list of available *measures* and required *context* for each
+For the staff-interactive checks we need a SPA (for AML):
-* Non-interactive measures (normal operation, account frozen) need:
+* to file forms and upload documentation (without state transition)
+* to decide on next measure (providing context); here, the exchange needs
+ to expose the list of available *measures* and required *context* for each
- * Expiration time (in context)
- * Measure to trigger upon expiration, again with context
- (renew documents, resume normal operation, etc.)
+For non-interactive measures (normal operation, account frozen) we need:
+* Expiration time (in context)
+* Measure to trigger upon expiration, again with context
+ (renew documents, resume normal operation, etc.)
We need some customer-driven interactivity in KYB/KYC process, for example the
user may need to be given choices (address vs. phone, individual vs. business,
order in which to provide KYC data of beneficiaries). As a result, the
-exchange needs to serve some "master" page for measures where the user is
-shown the next step(s) or choices (which person to collect KYC data on,
-whether to run challenger on phone number of physical address, etc.).
-That page should also potentially contain a form to allow the customer to
-directly upload documents to us (like business registration) instead of to
-some KYC provider. This is because KYC providers may not be flexible
-enough.
+exchange needs to serve some SPA for measures where the user is shown the next
+step(s) or choices (which person to collect KYC data on, whether to run
+challenger on phone number of physical address, etc.). The SPA should also
+potentially contain a form to allow the customer to directly upload documents
+to us (like business registration) instead of to some KYC provider. This is
+because KYC providers may not be flexible enough.
Similarly, the AML staff will need to be able to trigger rather complex
KYB/KYC processes, like "need KYC on X and Y and Z" or "phone number or
@@ -161,29 +203,6 @@ should be possible to request not only filled forms, but arbitrary
documents.
-Documentation
-^^^^^^^^^^^^^
-
-* We must define risk-profile (902.4, 905.1)
-* We must document the specific setup, likely not just the INI file
-* We probably should have some key AMLA file attributes, such as:
-
- * File opened, file closed (keep data for X years afterwards!)
- * low-risk or high-risk business relationship
- * PEP status
- * business domain
- * authority notification dates (possibly multiple) with
- voluntary or mandatory notification classification
-
-* There must be a page with an overview of AMLA files with opening
- and closing dates and an easy way to determine for any day the
- number of open AMLA files
-
-* Technically, we also need a list of at-risk transactions and of
- frozen transactions, but given that we can really only freeze
- on an account-basis, I think there is nothing to do here
-
-
Terminology
^^^^^^^^^^^
@@ -195,7 +214,7 @@ Terminology
* **Context**: Context is information provided as input into a *check* and *program* to customize their execution. The context is initially set by the *trigger*, but may evolve as the *account* undergoes *measures*. For each *check* and *program*, the required *context* data must be specified.
-* **Cost**: Metric for the business expense for a KYC check at a certain *provider*. Not in any currency, costs are simply relative and non-negative values. Costs are considered when multiple choices are allowed by the *configuration*.
+* **Cost**: How much would a client have to pay for a KYC process (if they voluntarily choose to do so for attestation).
* **Expiration**: KYC legitimizations may be outdated. Expiration rules determine when *checks* have to be performed again.
@@ -205,11 +224,11 @@ Terminology
* **Measure**: Describes the possible outgoing edges from one state in the state machine (including how to show the current state). Each edge is given some *context* and a *check* to be performed as well as a *program* to decide the *outcome* and the next *measure*.
-* **Outcome**: Describes the account state that an account ends up in due to the result of a *check*. Outcomes can be that an account is frozen (no transactions possible until freeze expires), held (no transactions possible until another *measure* has been taken), or operating normally.
+* **Outcome**: Describes the account state that an account ends up in due to the result of a *check*. Outcomes can be that an account is frozen (no transactions possible until freeze expires), held (no transactions possible until another *measure* has been taken), or operating normally. Outcomes also include a new set of *legitimization rules* to apply and an expiration time at which point a new *measure* will be automatically taken. Finally, parts of the outcome may be explained to the client (for example, to allow a wallet to stay below hard withdraw thresholds).
* **Provider**: A provider performs a specific set of *checks* at a certain *cost*. Interaction with a provider is performed by provider-specific *logic*.
-* **Program**: An AML helper *program* is given *context* about the current state of an account and the data from a *check* to compute the *outcome*. For example, a *program* may look at the "PEP" field of a KYC check and decide if the outcome is to put the account into ``normal`` or ``held-for-manual-review`` state. A *program* operating on an AML form filed by AML staff will likely be trivial and directly apply the explicit decision taken by the staff member.
+* **Program**: An AML helper *program* is given *context* about the current state of an account and the attribute data from a *check* to compute the *outcome*. For example, a *program* may look at the "PEP" field of a KYC check and decide if the outcome is to put the account into ``normal`` or ``held-for-manual-review`` state.
* **Type of operation**: The operation type determines which Taler-specific operation has triggered the KYC requirement. We support four types of operation: withdraw (by customer), deposit (by merchant), P2P receive (by wallet) and (high) wallet balance.
@@ -217,29 +236,7 @@ Terminology
New Endpoints
^^^^^^^^^^^^^
-We introduce a new ``wire_targets`` table into the exchange database. This
-table is referenced as the source or destination of payments (regular deposits
-and also P2P payments). A positive side-effect is that we reduce duplication
-in the ``reserves_in``, ``wire_out`` and ``deposits`` tables as they can
-reference this table.
-
-We introduce a new ``legitimization_processes`` table that tracks the status
-of a legitimization process at a provider, including the configuration section
-name, the user/account name at the provider, and some legitimization
-identifier for the process at the provider. In this table, we additionally
-store information related to the KYC status of the underlying payto://-URI, in
-particular when the KYC expires (0 if it was never done).
-
-Finally, we introduce a new ``legitimization_requirements`` table that
-contains a list of checks required for a particular wire target. When KYC is
-triggered (say when some endpoint returns an HTTP status code of 451) a
-new requirement is first put into the requirements table. Then, when the
-client identifies as business or individual the specific legitimization
-process is started. When the taler-exchange-aggregator triggers a KYC check
-the merchant can observe this when a 202 (Accepted) status code is returned
-on GET ``/deposits/`` with the respective legitimization requirement row.
-
-The new ``/kyc-check/`` endpoint is based on the legitimization requirements
+The ``/kyc-check/`` endpoint is based on the legitimization requirements
serial number and receives the business vs. individual status from the client.
Access is ``authenticated`` by also passing the hash of the payto://-URI.
(Weak authentication is acceptable, as the KYC status or the ability to
@@ -247,36 +244,340 @@ initiate a KYC process are not very sensitive.) Given this triplet, the
``/kyc-check/`` endpoint returns either the (positive) KYC status or redirects
the client (202) to the next required stage of the KYC process. The
redirection must be for an HTTP(S) endpoint to be triggered via a simple HTTP
-GET. As this endpoint is involved in every KYC check at the beginning, this
-is also the place where we can integrate the payment process for the KYC fee.
-
-The specific KYC provider to be executed depends on the configuration (see
-below) which specifies a ``$PROVIDER_SECTION`` for each authentication procedure.
-For each (enabled) provider, the exchange has a logic plugin which
-(asynchronously) determines the redirect URL for a given wire target. See
-below for a description of the high-level process for different providers.
-
-Upon completion of the process at the KYC provider, the provider must trigger
-a GET request to a new ``/kyc-proof/$H_PAYTO/$PROVIDER_SECTION`` endpoint.
-This may be done either by redirecting the browser of the user to that
-endpoint. Once this endpoint is triggered, the exchange will pass the
-received arguments to the respective logic plugin. The logic plugin will then
-(asynchronously) update the KYC status of the user. The logic plugin should
-return a human-readable HTML page with the KYC result to the user.
-
-Alternatively, the KYC confirmation may be triggered by a ``/kyc-webhook``
-request. As KYC providers do not necessarily support passing detailed
-information in the URL arguments, the ``/kyc-webhook`` only needs to specify
-either the ``PROVIDER_SECTION`` *or* the ``LOGIC`` (the name of the plugin
-implementing the KYC API). The API-specific webhook logic must then figure
-out what exactly the webhook is about on its own. The ``/kyc-webhook/``
-endpoint works for GET or POST, again as details depend on the KYC provider.
-In contrast to ``kyc-proof``, the response does NOT go to the end-users'
-browser and should thus only indicate success or failure.
-
-
-Legitimization Hooks
-^^^^^^^^^^^^^^^^^^^^
+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.
+
+FIXME: update /kyc-check/ endpoint to expose *public* outcomes of previous
+checks (such as hard withdrawal limits)!
+
+.. http:get:: /kyc-spa/{$HASH,$FILENAME}
+
+ A set of ``/kyc-spa/$HASH`` GET endpoints is created per client ``$HASH``
+ that serves the KYC SPA. This is where the ``/kyc-check/`` endpoint will
+ redirect clients unless all KYC/AML requirements are satisfied. The KYC SPA
+ will use the ``$HASH`` of its URL to initialize itself via the
+ ``/kyc-info/$HASH`` endpoint family. The KYC SPA may download additional
+ resources via ``/kyc-spa/$FILENAME``. The filenames must not match
+ base32-encoded SHA-512 hashes.
+
+.. http:get:: /kyc-info/$HASH
+
+ A new set of ``/kyc-info/$HASH`` GET endpoints is created per client
+ ``$HASH`` to return information about the state of the KYC or AML process to
+ the KYC SPA. The SPA uses this information to show the user an appropriate
+ dialog. The SPA should also long-poll this endpoint for changes to the AML/KYC
+ state. Note that this is a client-facing endpoint, so it will only provide a
+ restricted amount of information to the customer (as some laws may forbid us
+ to inform particular customers about their true status). The endpoint will
+ typically inform the SPA about possible choices to proceed, such as directly
+ uploading files, contacting AML staff, or proceeding with a particular KYC
+ process at an external provider (such as Challenger). If the user chooses to
+ initate a KYC process at an external provider, the SPA must request the
+ respective process to be set-up by the exchange via the ``/kyc-start/``
+ endpoint.
+
+ **Request**:
+
+ *If-None-Match*: The client MAY provide an ``If-None-Match`` header with
+ an ETag.
+
+ :query timeout_ms=MILLISECONDS: *Optional.* If specified, the exchange will wait up to MILLISECONDS for a change to a more recent legitimization measure before returning a 304 Not Modified.
+
+ **Response**:
+
+ :http:statuscode:`200 OK`:
+ The body is a `KycProcessClientInformation`.
+
+ *Etag*: Will be set to the serial ID of the measure. Used for long-polling.
+
+ .. ts:def:: KycProcessClientInformation
+
+ interface KycProcessClientInformation {
+
+ // List of requirements.
+ requirements?: { name : KycRequirementInformation};
+
+ // True if the client is expected to eventually satisfy all requirements.
+ // Default (if missing) is false.
+ is_and_combinator?: boolean
+
+ // List of available voluntary checks the client could pay for.
+ // Since **vATTEST**.
+ voluntary_checks?: { name : KycCheckInformation};
+ }
+
+ .. ts:def:: KycRequirementInformation
+
+ interface KycRequirementInformation {
+
+ // Which form should be used? Common values include "INFO"
+ // (to just show the descriptions but allow no action),
+ // "LINK" (to enable the user to obtain a link via
+ // ``/kyc-start/``) or any build-in form name supported
+ // by the SPA.
+ form: string;
+
+ // English description of the requirement.
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized
+ // description texts.
+ description_i18n ?: { [lang_tag: string]: string };
+
+ // ID of the requirement, useful to construct the
+ // ``/kyc-upload/$ID`` or ``/kyc-start/$ID`` endpoint URLs.
+ // Present if and only if "form" is not "INFO".
+ id?: string;
+
+ }
+
+ .. ts:def:: KycCheckInformation
+
+ // Since **vATTEST**.
+ interface KycCheckInformation {
+
+ // How much would this check cost the client?
+ cost: Amount;
+
+ // English description of the check.
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized
+ // description texts.
+ description_i18n ?: { [lang_tag: string]: string };
+
+ }
+
+ :http:statuscode:`204 No Content`:
+ There are no open KYC requirements or possible voluntary checks
+ the client might perform.
+
+ :http:statuscode:`304 Not Modified`:
+ The KYC requirements did not change.
+
+.. http:post:: /kyc-upload/$ID
+
+ The ``/kyc-upload/$ID`` POST endpoint allows the SPA to upload
+ client-provided evidence. The ``$ID`` will be provided as part of the
+ ``/kyc-info`` body. This is for checks of type ``FORM``.
+
+ **Request**:
+
+ Basically oriented along the possible formats of a HTTP form being
+ POSTed. Details will depend on the form. The server will try to
+ decode the uploaded body from whatever format it is provided in.
+
+ **Response**:
+
+ :http:statuscode:`204 No Content`:
+ The information was successfully uploaded. The SPA should fetch
+ an updated ``/kyc-info/``.
+ :http:statuscode:`404 Not Found`:
+ The ``$ID`` is unknown to the exchange.
+ :http:statuscode:`409 Conflict`:
+ The upload conflicts with a previous upload.
+ :http:statuscode:`413 Content Too Large`:
+ The body is too large.
+
+.. http:post:: /kyc-start/$ID
+
+ The ``/kyc-start/$ID`` POST endpoint allows the SPA to set up a new
+ external KYC process. It will return the URL that the client must GET
+ to begin the KYC process. The SPA should probably open this URL in a new
+ window or tab. The ``$ID`` will be provided as part of the ``/kyc-info``
+ body.
+
+ **Request**:
+
+ Use empty JSON body for now.
+
+ **Response**:
+
+ :http:statuscode:`200 Ok`:
+ The KYC process was successfully initiated. The URL is in a
+ `KycProcessStartInformation` object.
+
+ .. ts:def:: KycProcessStartInformation
+
+ interface KycProcessStartInformation {
+
+ // URL to open.
+ redirect_url: string;
+ }
+
+ :http:statuscode:`404 Not Found`:
+ The ``$ID`` is unknown to the exchange.
+
+ .. note::
+
+ As this endpoint is involved in every KYC check at the beginning, this
+ is also the place where we could integrate the payment process for the KYC fee
+ in the future (since **vATTEST**).
+
+
+.. http:get:: /kyc-proof/$H_PAYTO/$PROVIDER_SECTION
+
+ Upon completion of the process at the external KYC provider, the provider
+ must trigger a GET request to a new ``/kyc-proof/$H_PAYTO/$PROVIDER_SECTION``
+ endpoint. This may be done either by redirecting the browser of the user to
+ that endpoint. Once this endpoint is triggered, the exchange will pass the
+ received arguments to the respective logic plugin. The logic plugin will then
+ (asynchronously) update the KYC status of the user. The logic plugin should
+ return a human-readable HTML page with the KYC result to the user.
+
+.. http:get:: /kyc-webhook/*``
+.. http:post:: /kyc-webhook/*``
+
+ Alternatively, the KYC confirmation may be triggered by a ``/kyc-webhook``
+ request. As KYC providers do not necessarily support passing detailed
+ information in the URL arguments, the ``/kyc-webhook`` only needs to specify
+ either the ``PROVIDER_SECTION`` *or* the ``LOGIC`` (the name of the plugin
+ implementing the KYC API). The API-specific webhook logic must then figure
+ out what exactly the webhook is about on its own. The ``/kyc-webhook/``
+ endpoint works for GET or POST, again as details depend on the KYC provider.
+ In contrast to ``kyc-proof``, the response does NOT go to the end-users'
+ browser and should thus only indicate success or failure.
+
+.. http:post:: /wallet-kyc``
+
+ The ``/wallet-kyc`` POST endpoint allows a wallet to notify an exchange if
+ it will cross a balance threshold. Here, the ``balance`` specified should be
+ the threshold (from the ``wallet_balance_limit_without_kyc`` array) that the
+ wallet would cross, and *not* the *exact* balance of the wallet. The exchange
+ will respond with a wire target UUID. The wallet can then use this UUID to
+ being the KYC process at ``/kyc-check/``. The wallet must only proceed to
+ obtain funds exceeding the threshold after the KYC process has concluded.
+ While wallets could be "hacked" to bypass this measure (we cannot
+ cryptographically enforce this), such modifications are a terms of service
+ violation which may have legal consequences for the user.
+
+.. http:get:: /aml/$OFFICER_PUB/measures
+
+ To enable the AML staff SPA to give AML staff a choice of possible measures, a
+ new endpoint ``/aml/$OFFICER_PUB/measures`` is added that allows the AML SPA
+ to dynamically GET the list of available measures. It returns a list of known
+ KYC checks (by name) with their descriptions and a list of AML programs with
+ information about the required context.
+
+ **Request**:
+
+ FIXME: see other AML GET requests?
+
+ **Response**:
+
+ :http:statuscode:`200 Ok`:
+ Information about possible measures is returned in a
+ `AvailableMeasureSummary` object.
+
+ .. ts:def:: AvailableMeasureSummary
+
+ interface AvailableMeasureSummary {
+
+ // Available original measures that can be
+ // triggered directly by default rules.
+ roots: { "$measure_name" : MeasureInformation };
+
+ // Available AML programs.
+ programs: { "$prog_name" : AmlProgramRequirement };
+
+ // Available KYC checks.
+ checks: { "$check_name" : KycCheckInformation };
+
+ }
+
+ .. ts:def:: MeasureInformation
+
+ interface MeasureInformation {
+
+ // Name of a KYC check.
+ check_name: string;
+
+ // Name of an AML program.
+ prog_name: string;
+
+ // Context for the check. Could be empty.
+ context: Object;
+
+ }
+
+ .. ts:def:: AmlProgramRequirement
+
+ interface AmlProgramRequirement {
+
+ // Description of what the AML program does.
+ description: string;
+
+ // List of required field names in the context
+ // to run this AML program.
+ // SPA must check that the AML staff is providing
+ // adequate CONTEXT when defining a measure using
+ // this AML program.
+ context: string[];
+
+ // List of required attribute names in the
+ // input of this AML program. These attributes
+ // are the minimum that the check must produce
+ // (it may produce more).
+ inputs: string[];
+
+ }
+
+ .. ts:def:: KycCheckInformation
+
+ interface KycCheckInformation {
+
+ // Description of the KYC check. Should be shown
+ // to the AML staff but will also be shown to the
+ // client when they initiate the check in the KYC SPA.
+ description: string;
+ description_i18n: {};
+
+ // Names of the fields that the CONTEXT must provide
+ // as inputs to this check.
+ // SPA must check that the AML staff is providing
+ // adequate CONTEXT when defining a measure using
+ // this check.
+ requires: string[];
+
+ // Names of the attributes the check will output.
+ // SPA must check that the outputs match the
+ // required inputs when combining a KYC check
+ // with an AML program into a measure.
+ outputs: string[];
+
+ // Name of a root measure taken when this check fails.
+ fallback: string;
+ }
+
+.. http:get:: /aml/kyc-statistics/$NAME
+
+ Returns the number of KYC events matching the given
+ event type ``$NAME`` in the specified time range.
+ Note that this query can be slow as the statistics
+ are computed on-demand. (This is OK as such requests
+ should be rare.)
+
+ **Request**:
+
+ FIXME: add authorization checks, as with other /aml/ requests.
+
+ :query start_date=TIMESTAMP: *Optional*. Specifies the date when to start looking (inclusive). If not given, the start time of the exchange operation is used.
+ :query end_date=TIMESTAMP: *Optional*. Specifies the date when to stop looking (exclusive). If not given, the current date is used.
+
+ **Response**:
+
+ .. ts:def:: EventCounter
+
+ interface EventCounter {
+ // Number of events of the specified type in
+ // the given range.
+ cnt: Integer;
+ }
+
+
+Modifications to existing endpoints
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When withdrawing, the exchange checks if the KYC status is acceptable. If no
KYC was done and if either the amount withdrawn over a particular timeframe
@@ -305,93 +606,443 @@ account-reserve key pair. This should be the same key that is also used to
receive wallet-to-wallet payments. Then, *before* a wallet performs an
operation that would cause it to exceed the balance threshold in terms of
funds held from a particular exchange, it *should* first request the user to
-complete the KYC process.
-
-For that, the wallet should POST to the new ``/wallet-kyc`` endpoint,
-providing its long-term reserve-account public key and a signature requesting
-permission to exceed the account limit. Here, the ``balance`` specified should
-be the threshold (from the ``wallet_balance_limit_without_kyc`` array) that
-the wallet would cross, and *not* the *exact* balance of the wallet. The
-exchange will respond with a wire target UUID. The wallet can then use this
-UUID to being the KYC process at ``/kyc-check/``. The wallet must only proceed
-to obtain funds exceeding the threshold after the KYC process has
-concluded. While wallets could be "hacked" to bypass this measure (we cannot
-cryptographically enforce this), such modifications are a terms of service
-violation which may have legal consequences for the user.
-
-
-
-Configuration Options
-^^^^^^^^^^^^^^^^^^^^^
-
-The configuration specifies a set of providers, one per configuration section:
-
-[kyc-provider-$PROVIDER_ID]
-# Which plugin is responsible for this provider?
-LOGIC = PLUGIN_NAME
-# Which check does this provider provide?
-PROVIDED_CHECK = SMS
-# Plus additional logic-specific options, e.g.:
-AUTHORIZATION_TOKEN = superdupersecret
-FORM_ID = business_legi_form
-# How long is the data from this check considered valid?
-EXPIRATION = DURATION
-
-The configuration also specifies a set of legitimization
-requirements, one per configuration section:
-
-[kyc-legitimization-$RULE_NAME]
-# Operation that triggers this legitimization.
-# Must be one of WITHDRAW, DEPOSIT, P2P-RECEIVE
-# or WALLET-BALANCE.
-OPERATION_TYPE = WITHDRAW
-# Required measure to be performed.
-REQUIRED_MEASURE = SWISSNESS
-# Threshold amount above which the legitimization is
-# triggered. The total must be exceeded in the given
-# timeframe. Can be 'forever'.
-THRESHOLD = AMOUNT
-# Timeframe over which the amount to be compared to
-# the THRESHOLD is calculated.
-# Ignored for WALLET-BALANCE.
-TIMEFRAME = DURATION
-
-
-Finally, the configuration specifies a set of measures,
-one per configuration section:
-
-[aml-measure-$MEASURE_NAME]
-# Program to run on the context and check data to
-# determine the outcome and next measure.
-PROGRAM = /bin/true
-# Check to run as part of this measure. Optional.
-CHECK = CHECK_NAME
-# Form to show to the user as part of this measure.
-FORM = FORM_NAME
-
-For each FORM_NAME, there then must be
-
-* A HTML template (Mustach) that is instantiated with the
- JSON form context to produce a page to be shown to the user
-* A helper program (named after the form) that can:
-
- * Generate a list of required context attributes
- for the helper (!)
- * Validate and convert an input JSON with context
- attributes into the JSON form context
-
-
-Exchange Database Schema
+complete the KYC process. For that, the wallet should POST to the new
+``/wallet-kyc`` endpoint, providing its long-term reserve-account public key
+and a signature requesting permission to exceed the account limit.
+
+
+Configuration of external KYC providers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For each KYC provider that could contribute to checks the configuration
+specifies a ``$PROVIDER_SECTION`` for each authentication procedure. For each
+(enabled) provider, the exchange has a logic plugin which (asynchronously)
+determines the redirect URL for a given wire target. See below for a
+description of the high-level process for different providers.
+
+ .. code-block:: ini
+
+ [kyc-provider-$PROVIDER_ID]
+
+ # Which plugin is responsible for this provider?
+ LOGIC = PLUGIN_NAME
+
+ # Optional cost, useful if clients want to voluntarily
+ # trigger authentication procedures for attestation.
+ # 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
+ # if the provided inputs do not match expectations.
+ # Note that the converter will be expected to output the
+ # set of attributes listed under the respective ``[kyc-check-*]``
+ # sections. Calling the converter with ``--list-outputs``
+ # should generate a (newline-separated) list of attributes
+ # the converter promises to generate in its JSON output
+ # (when run regularly).
+ CONVERTER = taler-exchange-helper-$NAME
+
+
+Configuration of possible KYC/AML checks
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The configuration specifies a set of possible KYC checks offered by external
+providers, one per configuration section:
+
+ .. code-block:: ini
+
+ [kyc-check-$CHECK_NAME]
+
+ # Which type of check is this? Also determines
+ # the SPA form to show to the user for this check.
+ #
+ # INFO: wait for staff or contact staff out-of band
+ # (only information shown, no SPA action)
+ # FORM: SPA should show an inline (HTML) form
+ # LINK: SPA may start external KYC process or upload
+ #
+ TYPE = INFO|LINK|FORM
+
+ # Optional. Set to YES to allow this check be
+ # done voluntarily by a client (they may then
+ # still have to pay for it). Used to offer the
+ # SPA to display checks even if they are
+ # not required. Default is NO.
+ # Since **vATTEST**.
+ VOLUNTARY = YES/NO
+
+ # Provider id, present only if type is LINK.
+ PROVIDER_ID = id
+
+ # Name of the SPA form, if type is FORM
+ # "INFO" and "LINK" are reserved and must not be used.
+ # The exchange server and the SPA must agree on a list
+ # of supported forms and the resulting attributes.
+ #
+ # The SPA should include a JSON resource file
+ # "forms.json" mapping form names to arrays of
+ # attribute names each form provides.
+ FORM_NAME = name
+
+ # Descriptions to use in the SPA to display the check.
+ DESCRIPTION = "Upload your passport picture"
+ DESCRIPTION_I18N = "{"en":"Upload scan of your passport"}"
+
+ # ';'-separated list of fields that the CONTEXT must
+ # provided as inputs to this check. For example,
+ # for a FORM of type CHOICE, this might state
+ # ``choices: String[];``. The type after the ":"
+ # is for now purely for documentation and is
+ # not checked. However, it may be shown to AML staff
+ # when they configure measures.
+ REQUIRES = requirement;
+
+ # Description of the outputs provided by the check.
+ # Basically, the check's output is expected to
+ # provide the following fields as inputs into
+ # a subsequent AML program.
+ OUTPUTS = business_name street city country registration
+
+ # **original** measure to take if the check fails
+ # (for any reason, e.g. provider or form fail to
+ # satisfy constraints or provider signals user error)
+ # Usually should point to a measure that requests
+ # AML staff to investigate. The fallback measure
+ # context always includes the reasons for the
+ # failure.
+ FALLBACK = MEASURE_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``.
+
+
+Configuration of legitimization requirement triggers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The configuration also specifies a set of legitimization rules including the
+condition and the measure the condition triggers, one condition per
+configuration section:
+
+ .. code-block:: ini
+
+ [kyc-rule-$RULE_NAME]
+
+ # Operation that triggers this legitimization.
+ # Must be one of WITHDRAW, DEPOSIT, P2P-RECEIVE
+ # or WALLET-BALANCE.
+ OPERATION_TYPE = WITHDRAW
+
+ # 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 "verboten" is used if the
+ # threshold may never be crossed.
+ NEXT_MEASURES = SWISSNESS KYB
+
+ # Context for each of the above measures, optional.
+ MEASURE_CONTEXT_$NAME = CONTEXT
+
+ # "yes" if all REQUIRED_MEASURES will eventually need
+ # to be satisfied, "no" if the user has a choice between
+ # them. Not actually enforced by the exchange, but
+ # primarily used to inform the user whether this is
+ # an "and" or "or". YES for "and".
+ AND_COMBINATOR = YES
+
+ # YES if the rule (specifically, operation type,
+ # threshold, timeframe) and the general nature of
+ # the next measure (verboten or approval required)
+ # should be exposed to the client.
+ # Defaults to NO if not set.
+ EXPOSED = YES
+
+ # Threshold amount above which the legitimization is
+ # triggered. The total must be exceeded in the given
+ # timeframe. Can be 'forever'.
+ THRESHOLD = AMOUNT
+
+ # Timeframe over which the amount to be compared to
+ # the THRESHOLD is calculated.
+ # Ignored for WALLET-BALANCE.
+ TIMEFRAME = DURATION
+
+ # Enabled (default is NO)
+ ENABLED = NO
+
+
+AML programs
+^^^^^^^^^^^^
+
+AML programs are helper programs that can:
+
+* Generate a list of *required* context field names
+ for the helper (introspection!) using the "--required-context"
+ command-line switch. The output should use the same
+ syntax as the REQUIRES clause of ``[kyc-check-]``
+ configuration sections, except that new lines
+ MUST be used to separate fields instead of ";".
+* Generate a list of *required* attribute names
+ for the helper (introspection!) using the "--required-attributes"
+ command-line switch. The output should use the same
+ list of names as the ATTRIBUTES in the
+ ``[kyc-provider-]`` configuration section
+ (but may also include FORM field names).
+* Process an input JSON object of type
+ `AmlProgramInput` into a JSON object of
+ type `AmlProgramOutcome`.
+ 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.
+ // FIXME: review AmlDecisionDetail spec!
+ // (need to enable new outcomes!)
+ aml_history: AmlDecisionDetail[];
+
+ // JSON array with the results of historic
+ // KYC data about the account.
+ // FIXME: review KycDetail spec!
+ // (need to include AmlProgramOutcome!)
+ kyc_history: KycDetail[];
+
+ }
+
+.. ts:def:: AmlProgramOutcome
+
+ interface AmlProgramOutcome {
+
+ // Should the client's account be investigated
+ // by AML staff?
+ // Defaults to false.
+ to_investigate?: boolean;
+
+ // Should the client's account be frozen?
+ // Defaults to false.
+ is_frozen?: boolean;
+
+ // Was the client's account reported to the authorities?
+ // Defaults to false.
+ is_reported?: boolean;
+
+ // Free-form properties about the account.
+ // Can be used to store properties such as PEP,
+ // risk category, type of business, hits on
+ // sanctions lists, etc.
+ properties?: Object;
+
+ // Types of events to add to the KYC events table.
+ // (for statistics).
+ events?: string[];
+
+ // When does the outcome expire?
+ expiration: Timestamp;
+
+ // Name of the measure to apply the outcome expires.
+ // If not set, we revert to the default set
+ // of rules (and the default account state).
+ successor_measure: string;
+
+ // Array of KYC rules to apply. Note that this
+ // array overrides *all* of the default rules.
+ // Thus, if the array does not have an entry for
+ // a particular operation, there would be
+ // no thresholds for that operation!
+ rules: KycRule[];
+
+ // Custom measures that KYC rules may refer to.
+ custom_measures: { "name" : MeasureInformation };
+
+ }
+
+.. ts:def:: KycRule
+
+ interface KycRule {
+
+ // Type of operation to which the rule applies.
+ operation_type: String;
+
+ // Measure to be taken if the given
+ // threshold is crossed over the given timeframe.
+ threshold: Amount;
+
+ // Over which duration should the threshold be
+ // computed.
+ timeframe: RelativeTime;
+
+ // Array of names of measures to apply.
+ // Names listed can be original measures or
+ // custom measures from the `AmlProgramOutcome`.
+ // A special measure "verboten" is used if the
+ // threshold may never be crossed.
+ measures: String[];
+
+ // True if the rule (specifically, operation_type,
+ // threshold, timeframe) and the general nature of
+ // the measures (verboten or approval required)
+ // should be exposed to the client.
+ // Defaults to "false" if not set.
+ exposed?: boolean;
+
+ // True if all the measures will eventually need to
+ // be satisfied, false if any of the measures should
+ // do.
+ and_combinator: boolean;
+ }
+
+If the AML program fails (exits with a failure code or
+does not provide well-formed JSON output) the AML/KYC
+process continues with the FALLBACK measure. This should
+usually be one that asks AML staff to contact the
+systems administrator.
+
+AML programs are listed in the configuration file, one program per section:
+
+ .. code-block:: ini
+
+ [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
+
+
+Configuration of measures
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Finally, the 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.
+
+
+Sanity checking
+^^^^^^^^^^^^^^^
+
+On start-up, ``taler-exchange-httpd`` should sanity-check its
+configuration. Specifically, it should validate that for all AML programs the
+input requirements (attributes and context) are claimed to be satisfied by the
+respective checks that may trigger those programs, and similarly that for all
+checks the original measures satisfy the context requirements for their KYC
+checks.
+
+As a result, any component (AML program, form or external check) is warranted
+to be always called with the declared required inputs. Furthermore, we can
+detect if a component fails to produce the required output and the
+configuration contains (presumably safe) FALLBACKs to address this case. The
+exchange *MUST* detect circular failures, like when a FALLBACK triggers a
+measure that itself immediately triggers again the same FALLBACK.
+
+
+Exchange database schema
^^^^^^^^^^^^^^^^^^^^^^^^
+We introduce a new ``wire_targets`` table into the exchange database. This
+table is referenced as the source or destination of payments (regular deposits
+and also P2P payments). A positive side-effect is that we reduce duplication
+in the ``reserves_in``, ``wire_out`` and ``deposits`` tables as they can
+reference this table.
+
+We introduce a new ``legitimization_processes`` table that tracks the status
+of a legitimization process at a provider, including the configuration section
+name, the user/account name at the provider, and some legitimization
+identifier for the process at the provider. In this table, we additionally
+store information related to the KYC status of the underlying payto://-URI, in
+particular when the KYC expires (0 if it was never done).
+
+Finally, we introduce a new ``legitimization_requirements`` table that
+contains a list of checks required for a particular wire target. When KYC is
+triggered (say when some endpoint returns an HTTP status code of 451) a
+new requirement is first put into the requirements table. Then, when the
+client identifies as business or individual the specific legitimization
+process is started. When the taler-exchange-aggregator triggers a KYC check
+the merchant can observe this when a 202 (Accepted) status code is returned
+on GET ``/deposits/`` with the respective legitimization requirement row.
+
+
.. sourcecode:: sql
- CREATE TABLE IF NOT EXISTS wire_targets
- (wire_target_serial_id BIGSERIAL UNIQUE
- ,h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=64),
- ,payto_uri STRING NOT NULL
- ,PRIMARY KEY (h_payto)
- ) SHARD BY (h_payto);
+ CREATE TABLE wire_targets
+ (wire_target_serial_id BIGSERIAL UNIQUE
+ ,h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=64),
+ ,payto_uri STRING NOT NULL
+ ,PRIMARY KEY (h_payto)
+ )
+ PARTITION BY HASH (h_payto);
+
COMMENT ON TABLE wire_targets
IS 'All recipients of money via the exchange';
COMMENT ON COLUMN wire_targets.payto_uri
@@ -399,52 +1050,214 @@ Exchange Database Schema
COMMENT ON COLUMN wire_targets.h_payto
IS 'Unsalted hash of payto_uri';
- CREATE TABLE IF NOT EXISTS legitimization_requirements
- (legitimization_requirement_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
+ CREATE TABLE IF NOT EXISTS legitimization_measures
+ (legitimization_measure_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
,h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=32)
- ,required_checks VARCHAR NOT NULL
- ,UNIQUE (h_payto, required_checks);
- ) PARTITION BY HASH (h_payto);
-
- CREATE TABLE IF NOT EXISTS legitimization_processes
- (legitimization_serial_id BIGSERIAL UNIQUE
+ REFERENCES wire_targets (h_payto)
+ ,start_time INT8 NOT NULL
+ ,jmeasures VARCHAR[] NOT NULL
+ ,is_and_combinator BOOL NOT NULL DEFAULT(FALSE)
+ ,is_finished BOOL NOT NULL DEFAULT(FALSE)
+ )
+ PARTITION BY HASH (h_payto);
+
+ COMMENT ON COLUMN legitimization_requirements.start_time
+ IS 'Time when the measure was triggered (by decision or rule)';
+ COMMENT ON COLUMN legitimization_requirements.is_finished
+ IS 'Set to TRUE if this set of measures was processed; used to avoid indexing measures that are done';
+ COMMENT ON COLUMN legitimization_requirements.is_and_combinator
+ IS 'Set to TRUE each of the measures will ultimately need to be satisfied; FALSE if the user has the choice to satisfy one of them';
+ COMMENT ON COLUMN legitimization_requirements.jmeasures
+ IS 'array with KYC/AML measures for the account encoded in JSON';
+
+ CREATE INDEX ON legitimization_measures (h_payto)
+ WHERE NOT finished;
+
+ CREATE TABLE legitimization_outcomes
+ (outcome_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
+ ,h_payto BYTEA CHECK (LENGTH(h_payto)=32)
+ REFERENCES wire_targets (h_payto)
+ ,decision_time INT8 NOT NULL DEFAULT(0)
+ ,expiration_time INT8 NOT NULL DEFAULT(0)
+ ,jproperties VARCHAR,
+ ,to_investigate BOOL NOT NULL
+ ,is_frozen BOOL NOT NULL
+ ,is_reported BOOL NOT NULL
+ ,is_active BOOL NOT NULL DEFAULT(TRUE)
+ ,new_rules NOT NULL TEXT
+ )
+ PARTITION BY HASH (h_payto);
+
+ COMMENT ON TABLE legitimization_outcomes
+ IS 'Outcomes can come from AML programs';
+ COMMENT ON COLUMN legitimization_outcomes.h_payto
+ IS 'hash of the payto://-URI this outcome is about';
+ COMMENT ON COLUMN legitimization_outcomes.decision_time
+ IS 'when was this outcome decided';
+ COMMENT ON COLUMN legitimization_outcomes.expiration_time
+ IS 'time when the decision expires and the expiration new_rules should be applied';
+ COMMENT ON COLUMN legitimization_outcomes.jproperties
+ IS 'JSON with account properties, such as PEP status, business domain, risk assessment, etc.';
+ COMMENT ON COLUMN legitimization_outcomes.to_investigate
+ IS 'AML staff should investigate the activity of this account';
+ COMMENT ON COLUMN legitimization_outcomes.is_frozen
+ IS 'Transactions with this account should be held (until expiration data or AML staff action)';
+ COMMENT ON COLUMN legitimization_outcomes.is_reported
+ IS 'Set to TRUE if the activity of the account was reported to authorities';
+ COMMENT ON COLUMN legitimization_outcomes.is_active
+ IS 'TRUE if this is the current authoritative legitimization outcome';
+ COMMENT ON COLUMN legitimization_outcomes.new_rules
+ IS 'JSON array of KycRule objects to apply to the various operation types for this account; all KYC checks should first check if active new rules for a given account exist in this table (and apply specified measures); if not, it should check the default rules to decide if a measure is required';
+
+ CREATE INDEX legitimization_outcomes_active
+ ON legitimization_outcomes(h_payto)
+ WHERE is_active;
+
+ CREATE TABLE kyc_setups
+ (kyc_setup_serial_id BIGSERIAL UNIQUE
,h_payto BYTEA NOT NULL CHECK (LENGTH(h_payto)=64)
+ REFERENCES wire_targets (h_payto)
+ ,start_time INT8 NOT NULL
,expiration_time INT8 NOT NULL DEFAULT (0)
+ ,legitimization_measure_serial_id BIGINT
+ REFERENCES legitimization_measures (legitimization_measure_serial_id)
+ ,measure_index INT8'
,provider_section VARCHAR NOT NULL
,provider_user_id VARCHAR DEFAULT NULL
,provider_legitimization_id VARCHAR DEFAULT NULL
- ) PARTITION BY HASH (h_payto);
-
- COMMENT ON COLUMN legitimizations.legitimization_serial_id
- IS 'unique ID for this legitimization process at the exchange';
- COMMENT ON COLUMN legitimizations.h_payto
- IS 'foreign key linking the entry to the wire_targets table, NOT a primary key (multiple legitimizations are possible per wire target)';
- COMMENT ON COLUMN legitimizations.expiration_time
- IS 'in the future if the respective KYC check was passed successfully';
- COMMENT ON COLUMN legitimizations.provider_section
+ ,redirect_url TEXT DEFAULT NULL
+ ,finished BOOLEAN DEFAULT (FALSE)
+ )
+ PARTITION BY HASH (h_payto);
+
+ COMMENT ON TABLE kyc_setups
+ IS 'here we track KYC processes we initiated with external providers; the main reason is so that we do not initiate a second process when an equivalent one is still active; note that h_payto, provider_section, jcontext must match and the process must not be finished or expired for an existing redirect_url to be re-used; given that clients may voluntarily initiate KYC processes, there may not always be a legitimization_measure that triggered the setup';
+ COMMENT ON COLUMN kyc_setups.h_payto
+ IS 'foreign key linking the entry to the wire_targets table, NOT a primary key (multiple KYC setups are possible per wire target)';
+ COMMENT ON COLUMN kyc_setups.start_time
+ IS 'when was the legitimization process initiated';
+ COMMENT ON COLUMN kyc_setups.expiration_time
+ IS 'when does the process expire (and needs to be manually set up again)';
+ COMMENT ON COLUMN kyc_setups.measure_index
+ IS 'index of the measure in legitimization_measures that was selected for this KYC setup; NULL if legitimization_measure_serial_id is NULL; enables determination of the context data provided to the external process';
+ COMMENT ON COLUMN kyc_setups.provider_section
IS 'Configuration file section with details about this provider';
- COMMENT ON COLUMN legitimizations.provider_user_id
+ COMMENT ON COLUMN kyc_setups.provider_user_id
IS 'Identifier for the user at the provider that was used for the legitimization. NULL if provider is unaware.';
- COMMENT ON COLUMN legitimizations.provider_legitimization_id
+ COMMENT ON COLUMN kyc_setups.provider_legitimization_id
IS 'Identifier for the specific legitimization process at the provider. NULL if legitimization was not started.';
+ COMMENT ON COLUMN kyc_setups.legitimization_measure_serial_id
+ IS 'measure that enabled this setup, NULL if client voluntarily initiated the process';
+ COMMENT ON COLUMN kyc_setups.redirect_url
+ IS 'Where the user should be redirected for this external KYC process';
+ COMMENT ON COLUMN kyc_setups.finished
+ IS 'set to TRUE when the specific legitimization process is finished';
+
+ CREATE TABLE kyc_attributes
+ (kyc_attributes_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
+ ,h_payto BYTEA PRIMARY KEY CHECK (LENGTH(h_payto)=32)
+ REFERENCES wire_targets (h_payto)
+ ,kyc_prox BYTEA NOT NULL CHECK (LENGTH(kyc_prox)=32)
+ ,kyc_setup_serial_id INT8 NOT NULL
+ REFERENCES kyc_setups (kyc_setup_serial_id)
+ ,collection_time INT8 NOT NULL
+ ,expiration_time INT8 NOT NULL
+ ,trigger_outcome_serial INT8 NOT NULL
+ REFERENCES legitimization_outcomes(outcome_serial_id)
+ ,encrypted_attributes BYTEA NOT NULL
+ ) PARTITION BY HASH (h_payto);
+
+ COMMENT ON COLUMN kyc_attributes.h_payto
+ IS 'identifies the account this is about';
+ COMMENT ON COLUMN kyc_attributes.kyc_prox
+ IS 'for proximity search on encrypted data';
+ COMMENT ON COLUMN kyc_attributes.kyc_setup_serial_id
+ IS 'serial ID of the KYC setup that resulted in these attributes';
+ COMMENT ON COLUMN kyc_attributes.collection_time
+ IS 'when were these attributes collected';
+ COMMENT ON COLUMN kyc_attributes.expiration_time
+ IS 'when are these attributes expected to expire';
+ COMMENT ON COLUMN kyc_attributes.trigger_outcome_serial
+ IS 'ID of the outcome that was returned by the AML program based on the KYC data collected';
+ COMMENT ON COLUMN kyc_attributes.encrypted_attributes
+ IS 'encrypted JSON object with the attribute data the check provided';
+
+ CREATE TABLE aml_history
+ (aml_history_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
+ ,h_payto BYTEA CHECK (LENGTH(h_payto)=32)
+ REFERENCES wire_targets (h_payto)
+ ,legitimization_outcome INT8 NOT NULL
+ REFERENCES legitimization_outcomes (outcome_serial_id)
+ ,justification TEXT NOT NULL
+ ,decider_pub BYTEA CHECK (LENGTH(decider_pub)=32)
+ ,decider_sig BYTEA CHECK (LENGTH(decider_sig)=64);
+
+ COMMENT ON TABLE aml_history
+ IS 'Records decisions by AML staff with the respective signature and free-form justification.';
+ COMMENT ON COLUMN aml_history.legitimization_outcome
+ IS 'Actual outcome for the account (included in what decider_sig signs over)';
+ COMMENT ON COLUMN aml_history.decider_sig
+ IS 'Signature key of the staff member affirming the AML decision; of type AML_DECISION';
+
+ CREATE TABLE kyc_events
+ (event_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY
+ ,event_timestamp INT8 NOT NULL
+ ,event_type TEXT NOT NULL);
+
+ COMMENT ON TABLE kyc_events
+ IS 'Records of key events for statistics. Populated via triggers.';
+ COMMENT ON COLUMN kyc_events.event_type
+ IS 'Name of the event, such as account-open or sar-filed';
+
+ CREATE INDEX kyc_event_index
+ ON kyc_events(event_type,event_timestamp);
+
+KYC forms
+^^^^^^^^^
+
+The KYC SPA run by clients needs to support three TYPEs of checks. INFO is
+only about displaying the provided information, LINK is about setting up an
+exteral KYC check and redirecting there. FORM is about displaying a particular
+(HTML) form to the user and POSTing the entered information directly with the
+exchange. Here we describe the forms that must be supported:
+
+* CHOICE: Asks the client a multiple-choice question.
+ The context must include "choices: String[]" with
+ a list of choices to show. Used, for example, to
+ ask a client if they are an individual or a business.
+ The resulting HTML FORM field name must be
+ "choice" and it must be mapped to strings from the
+ choices list.
+* UPLOAD: Asks the client to upload a single file.
+ The context may include "extensions: String[]" with
+ a list of allowed file extensions the client's file
+ must end with (e.g. "png", "pdf", "gif"). In the
+ absence of this context, any file may be uploaded.
+ The context may also include "size_limit: Integer" with
+ the maximum file size in bytes that can be uploaded.
+ The resulting HTML FORM must have two fields,
+ "filename" and "filedata". "filename" must be
+ set to the basename of the original file (to the
+ extend that it is available), and "filedata"
+ to the base64-encoding of the uploaded data.
+
+As with other SPA checks, the KYC form should also show
+the description of the check.
Merchant modifications
^^^^^^^^^^^^^^^^^^^^^^
-A new setting is required where the merchant backend
-can be configured for a business (default) or individual.
-
-.. note::
-
- This still needs to be done!
+A new setting is required where the merchant backend can be configured for a
+business (default) or individual.
-We introduce new ``kyc_status``, ``kyc_timestamp`` and ``kyc_serial`` fields
-into a new table with primary keys ``exchange_url`` and ``account``. This
-status is updated whenever a deposit is created or tracked, or whenever the
-mechant backend receives a ``/kyc-check/`` response from the exchange. Initially,
-``kyc_serial`` is zero, indicating that the merchant has not yet made any
-deposits and thus does not have an account at the exchange.
+We introduce new ``kyc_ok``, ``aml_decision``, ``kyc_timestamp`` and
+``exchange_kyc_serial`` fields into a new table ``merchant_kyc`` with primary
+keys ``exchange_url`` and ``account_serial``. This status is updated whenever
+a deposit is created or tracked, or whenever the mechant backend receives a
+``/kyc-check/`` response from the exchange. Initially,
+``exchange_kyc_serial`` is zero, indicating that the merchant has not yet made
+any deposits and thus does not have an account at the exchange.
A new private endpoint ``/kyc`` is introduced which allows frontends to
request the ``/kyc`` status of any configured account (including with long
@@ -455,18 +1268,18 @@ either that the KYC is OK, or information (same as from the exchange endpoint)
to begin the KYC process.
The merchant backend uses the new field to remember that a KYC is pending
-(after ``/deposit``, or tracing deposits) and the SPA then shows a
+(after detection in ``taler-merchant-depositcheck``) and the SPA then shows a
notification whenever the staff is logged in to the system. The notification
can be hidden for the current day (remembered in local storage).
-The notification links to a (new) KYC status page. When opened, the KYC status
-page first re-checks the KYC status with the exchange. If the KYC is still
-unfinished, that page contains another link to begin the KYC process
-(redirecting to the OAuth 2.0 login page of the legitimization resource
-server), otherwise it shows that the KYC process is done. If the KYC is
-unfinished, the SPA should use long-polling on the KYC status on this page to
-ensure it is always up-to-date, and change to ``KYC satisfied`` should the
-long-poller return with positive news.
+The notification links to a (new) KYC status page. When opened, the KYC SPA
+first re-checks the KYC status with the exchange. If the KYC is still
+unfinished, that SPA will show forms, links or contact information to begin
+the KYC process (for example, redirecting to the OAuth 2.0 login page of the
+legitimization resource server), otherwise it shows that the KYC process is
+done. If the KYC is unfinished, the merchant SPA should use long-polling on
+the KYC status on this page to ensure it is always up-to-date, and change to
+``KYC satisfied`` should the long-poller return with positive news.
..note::
@@ -474,10 +1287,6 @@ long-poller return with positive news.
128-bit salt values (to keep ``deposits`` table small) and checks for salt
to be well-formed should be added "everywhere".
-An additional complication will arise once the exchange can trigger a KYC
-fee (402) on ``/kyc-check/``. In this case, the merchant SPA must show the QR
-code to the merchant to allow the merchant to pay the KYC fee with a wallet.
-
Bank requirements
@@ -496,8 +1305,8 @@ not on the name of the logic plugin (that we call ``$LOGIC``). Using the
configuration section, the exchange then determines the logic plugin to use.
This section describes the general API for all of the supported KYC providers,
-as well as some details of how this general API could be implemented by the logic for
-different APIs.
+as well as some details of how this general API could be implemented by the
+logic for different APIs.
General KYC Logic Plugin API
@@ -509,7 +1318,6 @@ This section provides a sketch of the proposed API for the KYC logic plugins.
- inputs:
+ provider_section (for additional configuration)
- + individual or business user
+ h_payto
- outputs:
+ success/provider-failure
@@ -638,6 +1446,40 @@ For ``/kyc-webhook/``:
to tell us anything for sure. The result is then returned.
+Types of KYC events
+^^^^^^^^^^^^^^^^^^^
+
+The ``/aml/kyc-statistics`` endpoint exposes statistics
+for various KYC event types.
+
+We will initially support the use of the following types
+of KYC events in the SPA (and have a dialog to show the
+total number of any of these for any specified time range):
+
+* account-open
+* account-closed
+* voluntary-sar
+* mandatory-sar
+* pep-started
+* pep-ended
+* risky-started
+* risky-ended
+* account-frozen
+* account-unfrozen
+
+Based on these, the SPA should also be albe to show active
+statistics (for any given timestamp) on the total number of:
+
+* open accounts
+* frozen accounts
+* high-risk accounts
+* PEPs served
+
+.. note::
+
+ This can be done by simply running the queries with
+ a start time of zero and subtracting.
+
Alternatives
============
diff --git a/design-documents/053-wallet-ui.rst b/design-documents/053-wallet-ui.rst
index bce8d1cd..7b5fdf73 100644
--- a/design-documents/053-wallet-ui.rst
+++ b/design-documents/053-wallet-ui.rst
@@ -172,17 +172,17 @@ Actions
Screenshots
^^^^^^^^^^^
-+-----------+----------------------------------------------------------------+
-| Platform | Screenshot |
-+===========+================================================================+
-| WebEx | .. image:: ../screenshots/cta-balance-list-firefox-latest.png |
-+-----------+----------------------------------------------------------------+
-| Android | .. image:: ../screenshots/cta-balance-list-android-latest.png |
-| | :width: 30% |
-+-----------+----------------------------------------------------------------+
-| iOS | .. image:: ../screenshots/cta-balance-list-ios-latest.png |
-| | :width: 30% |
-+-----------+----------------------------------------------------------------+
++-----------+------------------------------------------------------------------------+
+| Platform | Screenshot |
++===========+========================================================================+
+| WebEx | .. image:: ../screenshots/cta-balance-list-firefox-latest.png |
++-----------+------------------------------------------------------------------------+
+| Android | .. image:: ../screenshots/cta-balance-list-android-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------------+
+| iOS | .. image:: wallet-screenshots/ios-wallet/11-balances-list-latest.png |
+| | :width: 30% |
++-----------+------------------------------------------------------------------------+
.. _cta-transaction-list-ref:
@@ -303,7 +303,7 @@ Issues
* iOS (text): Sign of the operation (+ / -) should
be just before the amount (see Android), not
all the way on the left as an icon. Also can
- probably be more sublte?
+ probably be more subtle?
* iOS (text): currency symbol in front of every
amount value is highly redundant; would be better
to list the currency once in the title (see Android)
@@ -318,9 +318,6 @@ Issues
* all (text): "Deposits" should use the receiver name
of the payto-URI of the target account (URL-decoded)
in the main title, instead of "Deposit"
-* iOS (text): "Merchant" shown instead of merchant
- name for payments (unless "Merchant" is the merchant
- name here?)
* iOS (text): "Withdrawal" shown instead of
exchange URL for withdraw
* iOS (text): "Sent Requested money" shown instead of
diff --git a/design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-01.png b/design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-01.png
new file mode 100644
index 00000000..f6ff6bfc
--- /dev/null
+++ b/design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-01.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-latest.png b/design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-latest.png
new file mode 120000
index 00000000..69fa1dbb
--- /dev/null
+++ b/design-documents/wallet-screenshots/ios-wallet/10-empty-wallet-latest.png
@@ -0,0 +1 @@
+10-empty-wallet-01.png \ No newline at end of file
diff --git a/design-documents/wallet-screenshots/ios-wallet/11-balances-list-01.png b/design-documents/wallet-screenshots/ios-wallet/11-balances-list-01.png
new file mode 100644
index 00000000..1cd5e287
--- /dev/null
+++ b/design-documents/wallet-screenshots/ios-wallet/11-balances-list-01.png
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/11-balances-list-latest.png b/design-documents/wallet-screenshots/ios-wallet/11-balances-list-latest.png
new file mode 120000
index 00000000..93b135ab
--- /dev/null
+++ b/design-documents/wallet-screenshots/ios-wallet/11-balances-list-latest.png
@@ -0,0 +1 @@
+11-balances-list-01.png \ No newline at end of file
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-sheet130-withdraw-confirm.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-sheet130-withdraw-confirm.png
deleted file mode 100644
index 11dd9db0..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-sheet130-withdraw-confirm.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-sheet130-withdraw.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-sheet130-withdraw.png
deleted file mode 100644
index d46f0e5c..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-sheet130-withdraw.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-sheet133-withdraw-confirm-bank.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-sheet133-withdraw-confirm-bank.png
deleted file mode 100644
index 5d7dd8cd..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-sheet133-withdraw-confirm-bank.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-view22-balances.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-view22-balances.png
deleted file mode 100644
index 473621e8..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/CHF/cta-withdraw-view22-balances.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-confirm.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-confirm.png
deleted file mode 100644
index 4441777a..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-confirm.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-confirmed.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-confirmed.png
deleted file mode 100644
index c356eb13..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-confirmed.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-register.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-register.png
deleted file mode 100644
index e7b7c1f9..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-register.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-send-money.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-send-money.png
deleted file mode 100644
index 788ae7ab..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-send-money.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-withdraw.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-withdraw.png
deleted file mode 100644
index 74e1efff..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-bank-withdraw.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet130-withdraw-confirm.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet130-withdraw-confirm.png
deleted file mode 100644
index 22c57d66..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet130-withdraw-confirm.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet130-withdraw.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet130-withdraw.png
deleted file mode 100644
index 4f893fd4..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet130-withdraw.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet131-tos.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet131-tos.png
deleted file mode 100644
index 1aafc03e..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet131-tos.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet133-withdraw-confirm-bank.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet133-withdraw-confirm-bank.png
deleted file mode 100644
index 94ad63b1..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-sheet133-withdraw-confirm-bank.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-view10-empty-wallet.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-view10-empty-wallet.png
deleted file mode 100644
index a6737b9f..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-view10-empty-wallet.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-view22-balances.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-view22-balances.png
deleted file mode 100644
index bd83cb8f..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-bankIntegrated/cta-withdraw-view22-balances.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-amount.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-amount.png
deleted file mode 100644
index 9a51cb78..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-amount.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-wireTransfer-CHF-1.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-wireTransfer-CHF-1.png
deleted file mode 100644
index 1d9fdbfd..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-wireTransfer-CHF-1.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-wireTransfer-CHF-2.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-wireTransfer-CHF-2.png
deleted file mode 100644
index 3ea5b9ca..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-wireTransfer-CHF-2.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-wireTransfer-CHF-3.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-wireTransfer-CHF-3.png
deleted file mode 100644
index c15f9a5e..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet-wireTransfer-CHF-3.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-amount.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-amount.png
deleted file mode 100644
index 4db97e7c..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-amount.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-amount2.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-amount2.png
deleted file mode 100644
index 8c0d7f2a..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-amount2.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-tos.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-tos.png
deleted file mode 100644
index b71d7dcf..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-tos.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-CHF.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-CHF.png
deleted file mode 100644
index 8a467161..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-CHF.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-CHF2.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-CHF2.png
deleted file mode 100644
index 24bb4881..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-CHF2.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-NETZ.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-NETZ.png
deleted file mode 100644
index 7423411a..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-NETZ.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-NETZ2.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-NETZ2.png
deleted file mode 100644
index 80843838..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-wireTransfer-NETZ2.png
+++ /dev/null
Binary files differ
diff --git a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-withdraw-tos.png b/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-withdraw-tos.png
deleted file mode 100644
index 21056f08..00000000
--- a/design-documents/wallet-screenshots/ios-wallet/withdraw-exchange/cta-withdrawExchange-sheet135-withdraw-tos.png
+++ /dev/null
Binary files differ
diff --git a/frags/common-conf-syntax.rst b/frags/common-conf-syntax.rst
index 27c8ba87..2ca15058 100644
--- a/frags/common-conf-syntax.rst
+++ b/frags/common-conf-syntax.rst
@@ -46,14 +46,14 @@ from `GNU autoconf
values are usually dependent on an ``INSTALL_PREFIX`` which is determined by
the ``--prefix`` option given to configure. The canonical values are:
- * LIBEXECDIR = $INSTALL_PREFIX/taler/libexec/
- * DOCDIR = $INSTALL_PREFIX/share/doc/taler/
- * ICONDIR = $INSTALL_PREFIX/share/icons/
- * LOCALEDIR = $INSTALL_PREFIX/share/locale/
- * PREFIX = $INSTALL_PREFIX/
- * BINDIR = $INSTALL_PREFIX/bin/
- * LIBDIR = $INSTALL_PREFIX/lib/taler/
- * DATADIR = $INSTALL_PREFIX/share/taler/
+* LIBEXECDIR = $INSTALL_PREFIX/taler/libexec/
+* DOCDIR = $INSTALL_PREFIX/share/doc/taler/
+* ICONDIR = $INSTALL_PREFIX/share/icons/
+* LOCALEDIR = $INSTALL_PREFIX/share/locale/
+* PREFIX = $INSTALL_PREFIX/
+* BINDIR = $INSTALL_PREFIX/bin/
+* LIBDIR = $INSTALL_PREFIX/lib/taler/
+* DATADIR = $INSTALL_PREFIX/share/taler/
Note that on some platforms, the given paths may differ depending
on how the system was compiled or installed, the above are just the
diff --git a/frags/configuration-format.rst b/frags/configuration-format.rst
index 489e98cb..5a74c775 100644
--- a/frags/configuration-format.rst
+++ b/frags/configuration-format.rst
@@ -11,7 +11,7 @@ In order to override these defaults, the user can write a custom configuration
file and either pass it to the component at execution time using the *-c*
option, or name it taler.conf and place it under $HOME/.config/ which is where
components will look by default. Note that the systemd service files pass ``-c
-/etc/taler/taler.conf``, thus making ``/etc/taler/taler.conf``
+/etc/taler/taler.conf``, thus making ``/etc/taler/taler.conf``
the primary location for the configuration.
A config file is a text file containing sections, and each section
@@ -35,9 +35,9 @@ variables that are unset, by using the following syntax:
``${VAR:-default}``. There are two ways a user can set the value
of ``$``-prefixable variables:
- (1) by defining them under a ``[paths]`` section:
+(1) by defining them under a ``[paths]`` section:
- .. code-block:: ini
+ .. code-block:: ini
[paths]
TALER_DEPLOYMENT_SHARED = ${HOME}/shared-data
@@ -45,11 +45,11 @@ of ``$``-prefixable variables:
[section-x]
path-x = ${TALER_DEPLOYMENT_SHARED}/x
- (2) or by setting them in the environment:
+(2) or by setting them in the environment:
- .. code-block:: console
+ .. code-block:: console
- $ export VAR=/x
+ $ export VAR=/x
The configuration loader will give precedence to variables set under
``[path]`` over environment variables.
@@ -62,4 +62,3 @@ pathnames, when they use several levels of ``$``-expanded variables. See
The repository ``git://git.taler.net/deployment`` contains example code
for generating configuration files under ``deployment/netzbon/``.
-
diff --git a/frags/legal.rst b/frags/legal.rst
index dcecfaa0..be9b7f91 100644
--- a/frags/legal.rst
+++ b/frags/legal.rst
@@ -35,14 +35,14 @@ no terms of service available.
To configure the terms of service response, there are two options
in the configuration file for the service:
-- ``TERMS_ETAG``: The current "Etag" to return for the terms of service.
- This value must be changed whenever the terms of service are
- updated. A common value to use would be a version number.
- Note that if you change the ``TERMS_ETAG``, you MUST also provide
- the respective files in ``TERMS_DIR`` (see below).
-- ``TERMS_DIR``: The directory that contains the terms of service.
- The files in the directory must be readable to the service
- process.
+- ``TERMS_ETAG``: The current "Etag" to return for the terms of service.
+ This value must be changed whenever the terms of service are
+ updated. A common value to use would be a version number.
+ Note that if you change the ``TERMS_ETAG``, you MUST also provide
+ the respective files in ``TERMS_DIR`` (see below).
+- ``TERMS_DIR``: The directory that contains the terms of service.
+ The files in the directory must be readable to the service
+ process.
Privacy Policy
@@ -58,14 +58,14 @@ is no privacy policy available.
To configure the privacy policy response, there are two options
in the configuration file for the service:
-- ``PRIVACY_ETAG``: The current "Etag" to return for the privacy policy.
- This value must be changed whenever the privacy policy is
- updated. A common value to use would be a version number.
- Note that if you change the ``PRIVACY_ETAG``, you MUST also provide
- the respective files in ``PRIVACY_DIR`` (see below).
-- ``PRIVACY_DIR``: The directory that contains the privacy policy.
- The files in the directory must be readable to the service
- process.
+- ``PRIVACY_ETAG``: The current "Etag" to return for the privacy policy.
+ This value must be changed whenever the privacy policy is
+ updated. A common value to use would be a version number.
+ Note that if you change the ``PRIVACY_ETAG``, you MUST also provide
+ the respective files in ``PRIVACY_DIR`` (see below).
+- ``PRIVACY_DIR``: The directory that contains the privacy policy.
+ The files in the directory must be readable to the service
+ process.
Legal policies directory layout
diff --git a/manpages/libeufin-cli.1.rst b/manpages/libeufin-cli.1.rst
deleted file mode 100644
index 755c8b45..00000000
--- a/manpages/libeufin-cli.1.rst
+++ /dev/null
@@ -1,1006 +0,0 @@
-libeufin-cli(1)
-###############
-
-.. only:: html
-
- Name
- ====
-
- **libeufin-cli** - Interact with LibEuFin Sandbox and Nexus
-
-
-Synopsis
-========
-
-**libeufin-cli**
-[**-h** | **--help**]
-[**--version**]
-COMMAND [ARGS...]
-
-Commands: accounts, connections, facades, permissions, sandbox, users
-
-
-Description
-===========
-
-**libeufin-cli** is the user interface program to interact
-with **libeufin-sandbox** and **libeufin-nexus** when they are
-operating as HTTP servers, listening on localhost ports.
-Normally, you invoke them with their respective ``serve`` commands,
-and in a separate shell, use **libeufin-cli** to send requests
-and receive responses from them.
-
-The interaction model is as follows:
-
-- (Optionally) Start the sandbox.
-
-- Start the nexus.
-
-- Use **libeufin-cli** to interact with them.
- You can manage users and permissions, bank accounts, "facades",
- transactions, and connections between the various systems.
-
-For **libeufin-cli** to be able to communicate with **libeufin-sandbox**,
-the following environment variables need to be set:
-
-``LIBEUFIN_SANDBOX_USERNAME``
- This should normally be ``admin``.
-
-``LIBEUFIN_SANDBOX_PASSWORD``
- This is the same password chosen when the sandbox was started.
-
-``LIBEUFIN_SANDBOX_URL``
- This is ``http://localhost:PORT``, where ``PORT`` is the
- same port chosen when the sandbox was started.
- This URL can also be specified with the ``--sandbox-url URL``
- option to the ``sandbox`` command (see below).
- If both are given, the ``--sandbox-url`` option takes precedence.
-
-For **libeufin-cli** to be able to communicate with **libeufin-nexus**,
-the following environment variables need to be set:
-
-``LIBEUFIN_NEXUS_USERNAME``
- For some operations (such as ``users create``), this must be the
- same username chosen by the ``libeufin-nexus superuser`` command.
-
-``LIBEUFIN_NEXUS_PASSWORD``
- This is the password associated with the username.
-
-``LIBEUFIN_NEXUS_URL``
- This is ``http://localhost:PORT``, where ``PORT`` is the
- same port chosen when the nexus was started.
-
-Of the six commands, the ``sandbox`` command talks to the sandbox,
-while the other five commands talk to the nexus.
-The following sections describe each command and their subcommands in detail.
-
-
-sandbox
--------
-
-The ``libeufin-cli sandbox`` command is for managing the sandbox process
-started by ``libeufin-sandbox serve``.
-It takes one option, ``--sandbox-url URL``, to be specified before
-the subcommands and their arguments.
-This URL can also be specified with the ``LIBEUFIN_SANDBOX_URL``
-environment variable (see above).
-If both are given, the ``--sandbox-url`` option takes precedence.
-
-The following subcommands are available: bankaccount, check, demobank,
-ebicsbankaccount, ebicshost, ebicssubscriber.
-
-The first command to use is ``check``,
-followed by ``ebicshost``, ``ebicssubscriber``,
-and ``ebicsbankaccount``, to configure the basic system.
-
-You can then use the ``bankaccount`` command to generate (simulated)
-transaction traffic.
-
-After that, the ``demobank`` command and its subcommands
-provide the same access to the API that Nexus itself uses.
-You normally do not need to use those commands directly.
-
-
-sandbox check
--------------
-
-The ``check`` command attempts a simple aliveness check by
-contacting the sandbox and displaying its returned message.
-If all goes well, you should see something like:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox check
- Hello, this is the Sandbox
-
-
-sandbox ebicshost
------------------
-
-The ``ebicshost`` command manages EBICS hosts.
-It has two subcommands: create and list.
-
-sandbox ebicshost create
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``ebicshost create`` command creates a EBICS host.
-It takes one option, ``--host-id ID``, where ``ID`` is used to
-identify that host for all future commands.
-
-sandbox ebicshost list
-^^^^^^^^^^^^^^^^^^^^^^
-
-The ``ebicshost list`` command lists the hosts in the system.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox ebicshost create --host-id testhost
- $ libeufin-cli sandbox ebicshost list
- {
- "ebicsHosts" : [ "testhost" ]
- }
-
-Here, the ``ID`` is ``testhost``.
-
-
-sandbox ebicssubscriber
------------------------
-
-The ``ebicssubscriber`` command manages EBICS subscribers.
-It has two subcommands: create and list.
-
-sandbox ebicssubscriber create
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-NB: This command is deprecated and will be removed at some point.
-See ``sandbox demobank new-ebicssubscriber`` (below) for its replacement.
-
-The ``ebicssubscriber create`` command creates a EBICS subscriber.
-It takes three options, all of which are required:
-
-::
-
- --host-id TEXT Ebics host ID
- --partner-id TEXT Ebics partner ID
- --user-id TEXT Ebics user ID
-
-The host ID should be the same one specified in ``ebicshost create``
-(see above).
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox ebicssubscriber create \
- --host-id testhost \
- --partner-id partner01 \
- --user-id user01
-
-Note that ``testhost`` is the same as in the ``ebicshost create``
-example (see above).
-
-sandbox ebicssubscriber list
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``ebicssubscriber list`` command lists the EBICS subscribers
-in the system.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox ebicssubscriber list
- {
- "subscribers" : [ {
- "hostID" : "testhost",
- "partnerID" : "partner01",
- "userID" : "user01",
- "systemID" : null,
- "demobankAccountLabel" : "not associated yet"
- } ]
- }
-
-Note that the output reflects the subscriber created in
-the ``ebicssubscriber create`` example (see above).
-
-
-sandbox ebicsbankaccount
-------------------------
-
-The ``ebicsbankaccount`` command manages EBICS bank accounts.
-It has one subcommand: create.
-(To list accounts, see ``sandbox bankaccount`` below.)
-
-sandbox ebicsbankaccount
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``ebicsbankaccount create`` command takes several options, all required:
-
-::
-
- --iban TEXT IBAN
- --bic TEXT BIC
- --person-name TEXT bank account owner name
- --account-name TEXT label of this bank account
- --ebics-user-id TEXT user ID of the Ebics subscriber
- --ebics-host-id TEXT host ID of the Ebics subscriber
- --ebics-partner-id TEXT partner ID of the Ebics subscriber
-
-At this time, although the ``--person-name`` option is required,
-the sandbox does not remember the option value.
-(When queried, it displays "Bank account owner's name" instead.
-See ``sandbox bankaccount`` below.)
-For the sandbox, the important value is the ``--account-name`` option.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox ebicsbankaccount create \
- --iban DE18500105172929531888 \
- --bic INGDDEFFXXX \
- --person-name "Jane Normal" \
- --account-name testacct01 \
- --ebics-host-id testhost \
- --ebics-user-id user01 \
- --ebics-partner-id partner01
-
-Note that ``testhost`` is the same as in the ``ebicshost create``
-example, and that ``user01`` and ``partner01`` are the same as in the
-``ebicssubscriber create`` example (see above).
-
-
-sandbox bankaccount
--------------------
-
-The ``bankaccount`` command manages bank accounts.
-It has several subcommands: list, generate-transactions,
-simulate-incoming-transaction, transactions.
-
-sandbox bankaccount list
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``bankaccount list`` command lists the bank accounts in the system.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox bankaccount list
- [ {
- "label" : "bank",
- "name" : "Bank account owner's name",
- "iban" : "DE370758",
- "bic" : "SANDBOXX"
- }, {
- "label" : "testacct01",
- "name" : "Bank account owner's name",
- "iban" : "DE18500105172929531888",
- "bic" : "INGDDEFFXXX"
- } ]
-
-Note that ``testacct01``, ``DE18500105172929531888``, and ``INGDDEFFXXX``
-are the same as specified in the ``ebicsbankaccount create`` example
-(see above).
-
-sandbox bankaccount generate-transactions
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The remaining ``bankaccount`` commands deal with transactions
-to and from the bank accounts.
-
-The ``bankaccount generate-transactions`` command generates
-test transactions.
-It takes one arg, the account label.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox bankaccount generate-transactions testacct01
-
-Note that ``testacct01`` is the account label shown in the ``bankaccount
-list`` example (see above).
-
-sandbox bankaccount simulate-incoming-transaction
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``bankaccount simulate-incoming-transaction`` books an
-incoming payment in the sandbox.
-It takes one arg, the account label, and several options.
-
-::
-
- --debtor-iban TEXT IBAN sending the payment
- --debtor-bic TEXT BIC sending the payment
- --debtor-name TEXT name of the person who is sending the payment
- --amount TEXT amount, no currency
- --subject TEXT payment subject
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox bankaccount simulate-incoming-transaction
- testacct01 \
- --debtor-iban DE06500105174526623718 \
- --debtor-bic INGDDEFFXXX \
- --debtor-name "Joe Foo" \
- --subject "Hello World" \
- --amount 10.50
-
-Note that ``testacct01`` is the same as in previous examples (see above),
-and that ``10.50`` is in ``X.Y`` format.
-
-sandbox bankaccount transactions
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``bankaccount transactions`` command lists transactions.
-It takes one arg, the account label.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox bankaccount transactions testacct01
- {
- "payments" : [ {
- "account_label" : "testacct01",
- "creditor_iban" : "DE18500105172929531888",
- "creditor_bic" : "INGDDEFFXXX",
- "creditor_name" : "Creditor Name",
- "debtor_iban" : "DE64500105178797276788",
- "debtor_bic" : "DEUTDEBB101",
- "debtor_name" : "Max Mustermann",
- "amount" : "5",
- "currency" : "EUR",
- "subject" : "sample transaction DILWBJHL",
- "date" : "Wed, 26 Jan 2022 09:03:44 GMT",
- "credit_debit_indicator" : "credit",
- "account_servicer_reference" : "DILWBJHL",
- "paymentInformationId" : null
- }, {
- "account_label" : "testacct01",
- "creditor_iban" : "DE64500105178797276788",
- "creditor_bic" : "DEUTDEBB101",
- "creditor_name" : "Max Mustermann",
- "debtor_iban" : "DE18500105172929531888",
- "debtor_bic" : "INGDDEFFXXX",
- "debtor_name" : "Debitor Name",
- "amount" : "12",
- "currency" : "EUR",
- "subject" : "sample transaction N7JSY17B",
- "date" : "Wed, 26 Jan 2022 09:03:44 GMT",
- "credit_debit_indicator" : "debit",
- "account_servicer_reference" : "N7JSY17B",
- "paymentInformationId" : null
- }, {
- "account_label" : "testacct01",
- "creditor_iban" : "DE18500105172929531888",
- "creditor_bic" : "INGDDEFFXXX",
- "creditor_name" : "Creditor Name",
- "debtor_iban" : "DE06500105174526623718",
- "debtor_bic" : "INGDDEFFXXX",
- "debtor_name" : "Joe Foo",
- "amount" : "10.50",
- "currency" : "EUR",
- "subject" : "Hello World",
- "date" : "Wed, 26 Jan 2022 09:04:31 GMT",
- "credit_debit_indicator" : "credit",
- "account_servicer_reference" : "sandbox-6UI2J3636J9EESXO",
- "paymentInformationId" : null
- } ]
- }
-
-Note that ``testacct01`` is the same as in previous examples (see above),
-and that the generated transactions from previous examples are listed,
-as well.
-
-
-sandbox demobank
-----------------
-
-The ``demobank`` command provides an interface to the Access API,
-which includes three commands: register, info, new-transaction.
-There is also a fourth ``demobank`` command, new-ebicssubscriber,
-that does not use the Access API.
-
-For all ``demobank`` commands, the sandbox URL *must* specify which
-*one* bank the command applies to in the base URL.
-Note that this URL cannot be used with other sandbox commands.
-In other words:
-
-``--sandbox-url http://localhost:5016/demobanks/default``
- This base URL can be used for commands:
-
- - sandbox demobank register
- - sandbox demobank info
- - sandbox demobank new-ebicssubscriber
- - sandbox demobank new-transaction
-
- It specifies the ``default`` demobank.
-
-``--sandbox-url http://localhost:5016``
- This base URL can be used for all other sandbox commands.
-
-In the following examples, the base URL will be explicitly shown with
-the ``--sandbox-url`` option for the ``demobank`` commands.
-
-sandbox demobank register
-^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``demobank register`` command registers a new bank account.
-Note that the username will be both the username to login at
-the bank and the bank account label.
-It takes the username and password from the
-``LIBEUFIN_SANDBOX_USERNAME`` and ``LIBEUFIN_SANDBOX_PASSWORD``
-environment variables.
-The username *need not be* ``admin``.
-
-For example:
-
-.. code-block:: console
-
- $ export LIBEUFIN_SANDBOX_USERNAME=jrluser
- $ export LIBEUFIN_SANDBOX_PASSWORD=easy
- $ libeufin-cli sandbox \
- --sandbox-url http://localhost:5016/demobanks/default \
- demobank register
-
-sandbox demobank info
-^^^^^^^^^^^^^^^^^^^^^
-
-The ``demobank info`` command returns basic information on a bank account.
-It takes option ``--bank-account NAME``.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox \
- --sandbox-url http://localhost:5016/demobanks/default \
- demobank info --bank-account jrluser
- {
- "balance" : {
- "amount" : "EUR:100",
- "credit_debit_indicator" : "credit"
- },
- "paytoUri" : "payto://iban/SANDBOXX/DE948559?receiver-name=admin"
- }
-
-Note that ``jrluser`` is the same username / bank account name
-as in the ``register`` example (see above).
-
-sandbox demobank new-ebicssubscriber
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``demobank new-ebicssubscriber`` command associates a new Ebics
-subscriber to an existing bank account.
-It takes several options, all required:
-
-::
-
- --host-id TEXT Ebics host ID
- --partner-id TEXT Ebics partner ID
- --user-id TEXT Ebics user ID
- --bank-account TEXT Label of the bank account to associate
- with this Ebics subscriber
-
-For example:
-
-.. code-block: console
-
- $ libeufin-cli sandbox \
- --sandbox-url http://localhost:5016/demobanks/default \
- demobank new-ebicssubscriber \
- --host-id testhost \
- --partner-id partner01 \
- --user-id user02 \
- --bank-account jrluser
-
-Note that ``testhost`` is the same as in the ``ebicshost create``
-example, and that ``partner01`` is the same as in the
-``ebicssubscriber create`` example (see above).
-The ``user02`` is new.
-The ``--bank-account jrluser`` is the same as in the
-``info`` example (see above).
-You can see the effect of the ``new-ebicssubscriber`` command
-with the ``sandbox ebicssubscriber list``
-and ``sandbox bankaccount list`` commands.
-
-sandbox demobank new-transaction
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``demobank new-transaction`` command initiates a new transaction.
-It takes several options, all required:
-
-::
-
- --bank-account TEXT Label of the bank account to be
- debited for the transaction
- --payto-with-subject TEXT Payto address including the
- subject as a query parameter
- --amount CUR:X.Y Amount to transfer
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli sandbox \
- --sandbox-url http://localhost:5016/demobanks/default \
- demobank new-transaction \
- --bank-account jrluser \
- --payto-with-subject 'payto://FIXME/?message=1kg+coffee' \
- --amount EUR:10.50
- FIXME: Any output?
-
-Note that ``--bank-account jrluser`` is the same as in the
-``info`` and ``new-ebicssubscriber`` command examples (see above).
-
-
-connections
------------
-
-The ``connections`` set of commands handle connections between
-the bank(s) and Nexus.
-It has several subcommands:
-new-ebics-connection,
-list-connections,
-show-connection,
-delete-connection,
-export-backup,
-restore-backup,
-get-key-letter,
-connect,
-list-offered-bank-accounts,
-download-bank-accounts,
-import-bank-account.
-
-Generally, you will create a connection, save its critical key information
-to a safe location, then use the connection to find and import a bank
-account, for further use.
-
-Several commands take a ``CONNECTION_NAME`` argument.
-In the following examples, we use ``conn01`` for that.
-Also, for demonstration purposes, we use the sandbox EBICS services,
-so the ``EBICS_URL`` follows the previous examples in the ``sandbox``
-command, as the value of environment variable ``LIBEUFIN_SANDBOX_URL``
-suffixed with ``/ebicsweb``, i.e., ``http://localhost:5016/ebicsweb``.
-
-connections new-ebics-connection
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``connections new-ebics-connection`` command creates a new connection
-between an EBICS service and the Nexus.
-It takes one arg, the ``CONNECTION_NAME``, and four required options:
-
-::
-
- --ebics-url TEXT EBICS URL
- --host-id TEXT Host ID
- --partner-id TEXT Partner ID
- --ebics-user-id TEXT Ebics user ID
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli connections new-ebics-connection \
- --ebics-url http://localhost:5016/ebicsweb \
- --host-id testhost \
- --partner-id partner01 \
- --ebics-user-id user02 \
- conn01
-
-Note that the ``testhost``, ``partner01``, and ``user02`` are the same as
-in the ``sandbox demobank new-ebicssubscriber`` command (see above).
-
-connections list-connections
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``connections list-connections`` command lists connections in Nexus.
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli connections list-connections
- {
- "bankConnections" : [ {
- "name" : "conn01",
- "type" : "ebics"
- } ]
- }
-
-The name of the connection is ``conn01`` as in the
-``connections new-ebics-connection`` example (see above).
-
-connections show-connection
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``connections show-connection`` command displays information
-about a specific connection.
-It takes one argument, the ``CONNECTION_NAME``.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli connections show-connection conn01
- {
- "type" : "ebics",
- "owner" : "foo",
- "ready" : true,
- "details" : {
- "ebicsUrl" : "http://localhost:5016/ebicsweb",
- "ebicsHostId" : "testhost",
- "partnerId" : "partner01",
- "userId" : "user02"
- }
- }
-
-The details are the same as in the ``connections new-ebics-connections``
-example (see above).
-
-connections delete-connection
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``connections delete-connection`` command deletes a bank connection.
-It takes one argument, the ``CONNECTION_NAME``.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli connections delete-connection conn01
-
-connections export-backup
-^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``connections export-backup`` command writes key and signature
-information to a backup file (which you should take care to store
-in a secure location).
-It takes one argument, the ``CONNECTION_NAME`` and two required options:
-
-::
-
- --passphrase TEXT Passphrase for locking the backup
- --output-file TEXT Where to store the backup
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli connections export-backup \
- --passphrase secret \
- --output-file sig-and-key-info \
- conn01
- FIXME: Output?
-
-See: https://bugs.gnunet.org/view.php?id=7180
-
-connections restore-backup
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-connections get-key-letter
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``connections get-key-letter`` command creates a PDF file
-that contains key information.
-It takes two arguments, ``CONNECTION_NAME`` and ``OUTPUT_FILE``.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli connections get-key-letter conn01 key-letter.pdf
-
-This creates file ``key-letter.pdf`` in the current working directory.
-
-connections connect
-^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-connections list-offered-bank-accounts
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-connections download-bank-accounts
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-connections import-bank-account
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-
-users
------
-
-The ``libeufin-cli users`` command manages users authorized to
-operate Nexus.
-It has several subcommands: self, list, create, change-password.
-The ``create`` and ``change-password`` commands can only be issued
-by the superuser
-(as configured by the ``libeufin-nexus superuser`` command),
-while the ``self`` and ``list`` commands can be issued by any user.
-
-In the following ``users`` examples, we assume that previously
-the command ``libeufin-nexus superuser foo`` was issued, and
-that the current username and password are for that user
-(via environment variables ``LIBEUFIN_NEXUS_USERNAME`` and
-``LIBEUFIN_NEXUS_PASSWORD``, see above).
-
-users self
-^^^^^^^^^^
-
-The ``users self`` command displays information for the current user.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli users self
- {
- "username" : "foo",
- "superuser" : true
- }
-
-users list
-^^^^^^^^^^
-
-The ``users list`` command displays information for all the
-users authorized to operate Nexus.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli users list
- {
- "users" : [ {
- "username" : "foo",
- "superuser" : true
- } ]
- }
-
-In this example, there is only one user, the superuser ``foo``.
-
-users create
-^^^^^^^^^^^^
-
-The ``users create`` command creates a normal (non-superuser) user.
-It takes one argument, the ``USERNAME`` and one option,
-``--password TEXT``.
-If you omit the option, **libeufin-cli** will prompt you for the password.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli users create --password easy jrluser
- {
- "message" : "New user 'jrluser' registered"
- }
- $ libeufin-cli users list
- {
- "users" : [ {
- "username" : "foo",
- "superuser" : true
- }, {
- "username" : "jrluser",
- "superuser" : false
- } ]
- }
-
-In this example, we create the same user as for the sandbox examples
-(see above).
-Note that the system now includes two users.
-
-users change-password
-^^^^^^^^^^^^^^^^^^^^^
-
-The ``users change-password`` command changes the password for a user.
-It takes one argument, the ``USERNAME`` and one option,
-``--new-password TEXT``.
-If you omit the option, **libeufin-cli** will prompt you for the password.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli users change-password --new-password hard jrluser
- {
- "message" : "Password successfully changed"
- }
-
-
-permissions
------------
-
-The ``libeufin-cli permissions`` command manages permissions
-for operations on Nexus.
-It has three subcommands: list, grant, revoke.
-All three commands can only be issued by the superuser.
-
-permissions list
-^^^^^^^^^^^^^^^^
-
-The ``permissions list`` command lists the granted permissions.
-At the beginning of a session, there are none:
-
-.. code-block:: console
-
- $ libeufin-cli permissions list
- {
- "permissions" : [ ]
- }
-
-
-permissions grant
-^^^^^^^^^^^^^^^^^
-
-The ``permissions grant`` command adds a permission to the list
-of granted permissions.
-It takes five arguments: ``SUBJECT_TYPE``, ``SUBJECT_ID``,
-``RESOURCE_TYPE``, ``RESOURCE_ID``, ``PERMISSION_NAME``.
-
-FIXME: The subject type and id, resource type and id, are ...
-
-The ``PERMISSION_NAME`` is one of the following:
-
-- ``facade.talerwiregateway.history``
-- ``facade.talerwiregateway.transfer``
-- ``facade.anastasis.history``
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli permissions grant \
- some-subject-type some-subject-id \
- some-resource-type some-resource-id \
- facade.anastasis.history
- { }
- $ libeufin-cli permissions list
- {
- "permissions" : [ {
- "subject_type" : "some-subject-type",
- "subject_id" : "some-subject-id",
- "resource_type" : "some-resource-type",
- "resource_id" : "some-resource-id",
- "permission_name" : "facade.anastasis.history"
- } ]
- }
-
-permissions revoke
-^^^^^^^^^^^^^^^^^^
-
-The ``permissions revoke`` command does the opposite of the
-``permissions grant`` command.
-It takes the same arguments as the ``permissions grant`` command:
-``SUBJECT_TYPE``, ``SUBJECT_ID``, ``RESOURCE_TYPE``, ``RESOURCE_ID``,
-``PERMISSION_NAME``.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-cli permissions revoke \
- some-subject-type some-subject-id \
- some-resource-type some-resource-id \
- facade.anastasis.history
- { }
- $ libeufin-cli permissions list
- {
- "permissions" : [ ]
- }
-
-This example undoes the effect of the previous (``permissions grant``) example.
-
-
-accounts
---------
-
-WRITEME
-
-accounts transactions
-^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-accounts task-status
-^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-accounts task-schedule
-^^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-accounts task-delete
-^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-accounts submit-payments
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-accounts show-payment
-^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-accounts show
-^^^^^^^^^^^^^
-
-WRITEME
-
-accounts prepare-payment
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-accounts list-tasks
-^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-accounts list-payments
-^^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-accounts fetch-transactions
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-accounts delete-payment
-^^^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-
-facades
--------
-
-WRITEME
-
-facades new-taler-wire-gateway-facade
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-facades new-anastasis-facade
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-WRITEME
-
-facades list
-^^^^^^^^^^^^
-
-WRITEME
-
-
-See Also
-========
-
-.. TODO: libeufin-sandbox(1), libeufin-cli(1).
-
-
-Bugs
-====
-
-Report bugs by using https://bugs.taler.net or by sending electronic
-mail to <taler@gnu.org>.
diff --git a/manpages/libeufin-sandbox.1.rst b/manpages/libeufin-sandbox.1.rst
deleted file mode 100644
index 6f0948d0..00000000
--- a/manpages/libeufin-sandbox.1.rst
+++ /dev/null
@@ -1,227 +0,0 @@
-libeufin-sandbox(1)
-###################
-
-.. only:: html
-
- Name
- ====
-
- **libeufin-sandbox** - Simulate a banking system core
- with EBICS access to bank accounts
-
-
-Synopsis
-========
-
-**libeufin-sandbox**
-[**-h** | **--help**]
-[**--version**]
-COMMAND [ARGS...]
-
-Commands: serve, reset-tables, config, make-transaction, camt053tick
-default-exchange
-
-
-Description
-===========
-
-**libeufin-sandbox** is a program to simulate a banking system core
-with EBICS access to bank accounts.
-It maintains state in its own private database.
-You interact with it through HTTP
-requests either over the network or via a Unix domain socket.
-Related program **libeufin-cli** is the preferred front end
-for that mode of operation.
-There is also a mode where **libeufin-sandbox** accepts commands directly,
-useful for configuring one or more "demobank" (simulated bank) instances.
-
-Its options are as follows:
-
-**-h** \| **--help**
- Print short help on options.
-
-**–version**
- Print version information.
-
-The interaction model is as follows:
-
-.. @MS Is the order of the first two steps correct?
- Or are some of the commands to be used AFTER ‘serve’ starts?
- Or is it a mix? (I believe it is a mix, but am not sure.)
-
-- Configure the sandbox with commands ``config``, ``default-exchange``,
- ``make-transaction``, and ``camt053tick``.
-
-- Start the HTTP server with command ``serve``.
- Let this run in a shell, writing logs to stderr.
-
-- Point program **libeufin-nexus** at the sandbox.
-
-- Interact with **libeufin-nexus**.
-
-- When finished, interrupt the ``serve`` process and clean up with command
- ``reset-tables``.
-
-The following sections describe each command in detail.
-
-
-config
-------
-
-This command takes argument ``NAME`` and creates a demobank with that name.
-
-Option ``--currency CUR`` (default: ``EUR``) specifies another currency.
-Option ``--captcha-url $URL`` specifies where the wallet user is going
-to be redirected to confirm the withdrawal operation. This $URL should
-point to the bank frontend. More precisely to the UI that let the user
-finish a withdrawal operation that needs to be confirmed. Example of
-this value may be "https://bank.domain/#/operation/{wopid}" where
-"https://bank.domain" returns the demobank SPA and the demobank view under
-the route "/operation/{wopid}" will show the status of the operation id {wopid}.
-Note that "{wopid}" is literally in the --captcha-url config and replaced at
-runtime by the sandbox server.
-Option ``--bank-debt-limit N`` (default: 1000000) specifies that
-the bank debt limit should be N (units of currency).
-Similarly, option ``--users-debt-limit N`` (default: 1000) specifies
-that the users debt limit should be N (units of currency).
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-sandbox config default
-
-This creates the demobank ``default`` with currency ``EUR``,
-bank debt limit 1000000, users debt limit 1000,
-and allows registrations.
-
-
-default-exchange
-----------------
-
-This command sets the exchange that a demobank will suggest to wallets.
-(Wallets are of course free to disregard the suggestion and choose
-another exchange.)
-It requires two arguments, ``EXCHANGE-BASEURL`` and ``EXCHANGE-PAYTO``.
-The option ``--demobank NAME`` (default: ``default``) specifies
-which demobank this setting affects.
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-sandbox default-exchange \
- --demobank bank01 \
- https://exchange.example.com/ \
- payto://iban/CH9300762011623852957
-
-This sets the default exchange for demobank ``bank01``.
-It is an error if the demobank does not exist.
-
-
-make-transaction
-----------------
-
-This is a "legacy" command, useful in a previous iteration of LibEuFin
-and for internal testing.
-It creates and records a wire transfer transaction in the database.
-
-It takes two arguments and several required options.
-The arguments are ``AMOUNT``, in ``CUR:X.Y`` format;
-and ``SUBJECT``, a short textual description of the transaction.
-The options are: ``--credit-account LABEL`` and ``--debit-account LABEL``,
-where each LABEL names a bank account for receiving and issuing,
-respectively, the wire transfer.
-The option ``--demobank NAME`` (default: ``default``) specifies
-in which demobank the wire transfer occurs.
-
-.. note::
-
- If you have not yet called ``config``, this command creates
- a demobank named ``default`` on its first use. The currency,
- and bank debt limit have the same defaults as for the ``config``
- command. The users debt limit, however, defaults to 10000.
-
-FIXME: How to achieve the same result with **libeufin-cli**?
-
-
-camt053tick
------------
-
-This command advances the internal time step that the demobank
-uses to group transactions for reporting.
-(Successive transactions will be inserted in a new Camt.053 report.)
-
-For example:
-
-.. code-block:: console
-
- $ libeufin-sandbox camt053tick
-
-FIXME: How to achieve the same result with **libeufin-cli**?
-
-
-serve
------
-
-This command starts the HTTP server, listening on port 5000.
-To use a different port, use option ``--port INT``.
-To listen, instead, on a Unix domain socket,
-use option ``--with-unix-socket PATH``.
-When both ``--port`` and ``--with-unix-socket`` are given,
-``--with-unix-socket`` takes precedence.
-
-.. note::
-
- If you have not yet called ``config``, this command creates
- a demobank named ``default`` on its first use. The currency,
- and bank debt limit have the same defaults as for the ``config``
- command. The users debt limit, however, defaults to 10000.
-
-The process runs in the foreground, writing its logs to standard error.
-The normal log level is ``DEBUG``.
-To change it, use ``--log-level LEVEL``, where ``LEVEL`` is one of:
-``ERROR``, ``WARN``, ``INFO``, ``DEBUG``, ``TRACE``.
-
-Before invoking ``serve``, the following environment variables need to be set:
-
-``LIBEUFIN_SANDBOX_ADMIN_PASSWORD``
- The password required for later use by **libeufin-cli**.
- For testing purposes, you can use option ``--no-auth`` to disable
- this requirement.
- (In that case, this environment variable need not be set.)
-
-``LIBEUFIN_SANDBOX_DB_CONNECTION``
- This specifies the database **libeufin-sandbox** uses to maintain state.
- Currently, both Sqlite and PostgreSQL are supported.
- (Only one needs to be specified.)
- Examples:
-
- - ``jdbc:sqlite:/tmp/libeufin-sandbox.db``
- - ``jdbc:postgresql://localhost:5432/libeufindb?user=Foo&password=secret``
-
-Normally, the ``serve`` command runs until interrupted.
-When run in a shell, you can use ``Control-C`` for that.
-
-
-reset-tables
-------------
-
-This command drops all the tables in the internal database.
-(The next time the tables are needed, **libeufin-sandbox** creates them
-again, automatically.)
-
-It should only be used when the sandbox is quiescent.
-
-
-See Also
-========
-
-.. TODO: libeufin-nexus(1), libeufin-cli(1).
-
-
-Bugs
-====
-
-Report bugs by using https://bugs.taler.net or by sending electronic
-mail to <taler@gnu.org>.
diff --git a/taler-challenger-manual.rst b/taler-challenger-manual.rst
index 39b06710..f9d6a793 100644
--- a/taler-challenger-manual.rst
+++ b/taler-challenger-manual.rst
@@ -225,9 +225,9 @@ Fundamental Setup: Address validation
Each challenger service is designed to validate one type of address. Possible
address types include:
- * phone numbers (via SMS)
- * e-mail addresses (via SMTP)
- * mail addresses (via postal service)
+* phone numbers (via SMS)
+* e-mail addresses (via SMTP)
+* mail addresses (via postal service)
In principle, additional types of addresses can easily be added by extending
the respective HTML and programs to send challenges to the new address type.
@@ -235,17 +235,17 @@ the respective HTML and programs to send challenges to the new address type.
To make different types of address validations possible, the Challenger
configuration contains two configuration options.
- (1) The ``ADDRESS_TYPE`` configuration option informs Challenger about the
- type of address it is expected to validate. It is returned as part of
- the OAuth 2.0 ``/info`` endpoint to the client, and is typically also
- used when deciding how to render the HTML form for address entry that is
- shown to the user.
+(1) The ``ADDRESS_TYPE`` configuration option informs Challenger about the
+ type of address it is expected to validate. It is returned as part of
+ the OAuth 2.0 ``/info`` endpoint to the client, and is typically also
+ used when deciding how to render the HTML form for address entry that is
+ shown to the user.
- (2) The ``AUTH_COMMAND`` configuration option specifies which command
- Challenger should run to send a challenge to an address. The actual
- address is given to this subcommand as the first argument (``$1``),
- while the text with the challenge is passed to standard input.
- The subcommand should terminate with a status code of 0 on success.
+(2) The ``AUTH_COMMAND`` configuration option specifies which command
+ Challenger should run to send a challenge to an address. The actual
+ address is given to this subcommand as the first argument (``$1``),
+ while the text with the challenge is passed to standard input.
+ The subcommand should terminate with a status code of 0 on success.
.. code-block:: ini
:caption: /etc/challenger/challenger.conf
@@ -264,10 +264,10 @@ the SMS and postal mail scripts before they can function. In any case, these
scripts should be primarily seen as *examples* on how to write authentication
commands.
- ..note::
+.. note::
- We strongly welcome contributions for additional scripts with alternative
- providers or for new types of addresses.
+ We strongly welcome contributions for additional scripts with alternative
+ providers or for new types of addresses.
Legal conditions for using the service
@@ -326,15 +326,15 @@ to be initialized with the following command:
[root@exchange-online]# sudo -u challenger-httpd challenger-dbinit
- ..note::
+.. note::
- To run this command, the user must have ``CREATE TABLE``, ``CREATE
- INDEX``, ``ALTER TABLE`` and (in the future possibly even) ``DROP TABLE``
- permissions. Those permissions are only required for this step (which may
- have to be repeated when upgrading a deployment). Afterwards, during
- normal operation, permissions to ``CREATE`` or ``ALTER`` tables are not
- required by Challenger and thus should not be granted. For more
- information, see :doc:`manpages/challenger-dbinit.1`.
+ To run this command, the user must have ``CREATE TABLE``, ``CREATE
+ INDEX``, ``ALTER TABLE`` and (in the future possibly even) ``DROP TABLE``
+ permissions. Those permissions are only required for this step (which may
+ have to be repeated when upgrading a deployment). Afterwards, during
+ normal operation, permissions to ``CREATE`` or ``ALTER`` tables are not
+ required by Challenger and thus should not be granted. For more
+ information, see :doc:`manpages/challenger-dbinit.1`.
Deployment
@@ -402,10 +402,11 @@ have terminated unexpectedly. Furthermore, the hypervisor
to limit Postgres database memory utilization.
.. note::
- The ``challenger-httpd`` does not ship with HTTPS enabled by default.
- It must thus be run behind an HTTPS reverse proxy that performs
- TLS termination on the same system. Thus, it would typically be configured
- to listen on a UNIX domain socket.
+
+ The ``challenger-httpd`` does not ship with HTTPS enabled by default.
+ It must thus be run behind an HTTPS reverse proxy that performs
+ TLS termination on the same system. Thus, it would typically be configured
+ to listen on a UNIX domain socket.
Given proper packaging, all of the above are realized via a simple systemd
target. This enables Challenger to be properly started using a simple command:
@@ -422,13 +423,13 @@ Before clients can use Challenger, they must be explicitly configured. Each
client is identified via its OAuth 2.0 REDIRECT URI. Thus, a client must have
exactly one REDIRECT URI
- ..note::
+.. note::
- The OAuth 2.0 specification allows for a client to register
- zero or multiple REDIRECT URIs. However, zero is insecure
- as it creates an open redirector, and multiple REDIRECT URIs
- can trivially be implemented with Challenger by adding more
- clients.
+ The OAuth 2.0 specification allows for a client to register
+ zero or multiple REDIRECT URIs. However, zero is insecure
+ as it creates an open redirector, and multiple REDIRECT URIs
+ can trivially be implemented with Challenger by adding more
+ clients.
You can add or remove clients at any time; the Challenger service does not
need to be running, but if it is you can still add or remove clients without
@@ -460,12 +461,12 @@ info endpoints. For Challenger, these are ``/authorize``, ``/token`` and
``/authorize/$NONCE`` where ``$NONCE`` is a nonce that must be first requested
by the client using the ``/setup/$CLIENT_ID`` endpoint!
- ..note::
+.. note::
- This extra step prevents user-agents from (ab)using the Challenger service
- to send challenges to addresses even when there is no authorized client
- that desires address validation. This is an important feature as address
- validation could be expensive.
+ This extra step prevents user-agents from (ab)using the Challenger service
+ to send challenges to addresses even when there is no authorized client
+ that desires address validation. This is an important feature as address
+ validation could be expensive.
Thus, to generate the authorization URL, a client must first POST to
``/setup/$CLIENT_ID`` using their client secret in an ``Authorization: Bearer $SECRET``
@@ -493,10 +494,10 @@ the configuration file syntax:
Database management
-------------------
- .. note::
+.. note::
- We advise to make good backups before experimenting with
- the database.
+ We advise to make good backups before experimenting with
+ the database.
To update the Challenger database after upgrading to a newer
version of Challenger, you should simply re-run ``challenger-dbinit``.
@@ -532,8 +533,8 @@ Template Customization
======================
The Challenger service comes with various HTML templates that are shown to
-guide users through the process. Challenger uses `Mustach
-<https://gitlab.com/jbol/mustach>`__ as the templating engine. This section
+guide users through the process. Challenger uses `C implementation of mustache
+<https://gitlab.com/jobol/mustach>`__ as the templating engine. This section
describes the various templates. In general, the templates must be installed
to the ``share/challenger/templates/`` directory. The file names must be of
the form ``$NAME.$LANG.must`` where ``$NAME`` is the name of the template and
@@ -545,6 +546,8 @@ exists, the correct language will be automatically served.
The following subsections give details about each of the templates. The
subsection title is the ``$NAME`` of the respective template.
+.. _challenger_enter-address_type-form:
+
enter-$ADDRESS_TYPE-form
------------------------
@@ -558,18 +561,25 @@ file) is also supported.
The template is instantiated using the following information:
- * restrictions: Object; map of keys (names of the fields of the address to be entered by the user) to objects with a "regex" (string) containing an extended Posix regular expression for allowed address field values, and a "hint"/"hint_i18n" giving a human-readable explanation to display if the value entered by the user does not match the regex. Keys that are not mapped to such an object have no restriction on the value provided by the user. See "ADDRESS_RESTRICTIONS" in the challenger configuration.
- * fix_address: boolean; indicates if the given address cannot be changed
- anymore, the form should be read-only if set to true.
-
- * nonce: String; unique value identifying the challenge, should be shown
- to the user so that they can recognize it when they receive the TAN code
-
- * last_address: Object; form values from the previous submission if available,
- details depend on the ``ADDRESS_TYPE``, should be used to pre-populate the form
-
- * changes_left: Integer; number of times the address can still be changed,
- may or may not be shown to the user
+* restrictions: Object; map of keys (names of the fields of the
+ address to be entered by the user) to objects with a "regex"
+ (string) containing an extended Posix regular expression for
+ allowed address field values, and a "hint"/"hint_i18n" giving
+ a human-readable explanation to display if the value entered
+ by the user does not match the regex. Keys that are not mapped
+ to such an object have no restriction on the value provided by
+ the user. See "ADDRESS_RESTRICTIONS" in the challenger
+ configuration.
+* fix_address: boolean; indicates if the given address cannot be changed
+ anymore, the form should be read-only if set to true.
+* nonce: String; unique value identifying the challenge, should be shown
+ to the user so that they can recognize it when they receive the TAN code
+* last_address: Object; form values from the previous submission if available,
+ details depend on the ``ADDRESS_TYPE``, should be used to pre-populate the form
+* changes_left: Integer; number of times the address can still be changed,
+ may or may not be shown to the user
+
+.. _challenger_enter-tan-form:
enter-tan-form
--------------
@@ -579,23 +589,21 @@ that they received at the respective address.
The template is instantiated using the following information:
- * nonce: String; unique value identifying the challenge, should be shown
- to the user so that they can match it to the TAN code they received
-
- * attempts_left: Integer; how many more attempts are allowed, might be
- shown to the user, highlighting might be appropriate for low values
- such as 1 or 2 (the form will never be used if the value is zero)
-
- * address: Object; the address that is being validated, might be shown
- or not
-
- * transmitted: boolean; true if we just retransmitted the challenge,
- false if we sent a challenge recently and thus refused to transmit it
- again this time; might make a useful hint to the user
+* nonce: String; unique value identifying the challenge, should be shown
+ to the user so that they can match it to the TAN code they received
+* attempts_left: Integer; how many more attempts are allowed, might be
+ shown to the user, highlighting might be appropriate for low values
+ such as 1 or 2 (the form will never be used if the value is zero)
+* address: Object; the address that is being validated, might be shown
+ or not
+* transmitted: boolean; true if we just retransmitted the challenge,
+ false if we sent a challenge recently and thus refused to transmit it
+ again this time; might make a useful hint to the user
+* next_tx_time: String; timestamp explaining when we would re-transmit
+ the challenge the next time (at the earliest) if requested by the user
- * next_tx_time: String; timestamp explaining when we would re-transmit
- the challenge the next time (at the earliest) if requested by the user
+.. _challenger_invalid-pin:
invalid-pin
-----------
@@ -604,25 +612,22 @@ The user has provided an invalid TAN code (HTTP 403 Forbidden).
The template is instantiated using the following information:
- * ec: Integer; numeric Taler error code, should be shown to indicate the
- error compactly for reporting to developers
-
- * hint: String; human-readable Taler error code, should be shown for the
- user to understand the error
-
- * addresses_left: Integer; how many times is the user still allowed to
- change the address; if 0, the user should not be shown a link to jump
- to the address entry form
-
- * pin_transmissions_left: Integer; how many times might the PIN still
- be retransmitted
-
- * auth_attempts_left: Integer; how many times might the user still try
- entering the PIN code
-
- * exhausted: Bool; if true, the PIN was not even evaluated as the user previously exhausted the number of attempts
-
- * no_challenge: Bool; if true, the PIN was not even evaluated as no challenge was ever issued (the user must have skipped the step of providing their address first!)
+* ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+* hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+* addresses_left: Integer; how many times is the user still allowed to
+ change the address; if 0, the user should not be shown a link to jump
+ to the address entry form
+* pin_transmissions_left: Integer; how many times might the PIN still
+ be retransmitted
+* auth_attempts_left: Integer; how many times might the user still try
+ entering the PIN code
+* exhausted: Bool; if true, the PIN was not even evaluated as the user
+ previously exhausted the number of attempts
+* no_challenge: Bool; if true, the PIN was not even evaluated as no
+ challenge was ever issued (the user must have skipped the step of
+ providing their address first!)
If both *pin_transmissions_left* and *auth_attempts_left* are zero, the link
to re-enter the PIN should be hidden and the user should only be allowed to
@@ -631,6 +636,8 @@ values are zero. (Thus there is always at least one valid choice when the form
is shown.)
+.. _challenger_validation-unknown:
+
validation-unknown
------------------
@@ -639,15 +646,14 @@ backend (HTTP 404 Not Found).
The template is instantiated using the following information:
- * ec: Integer; numeric Taler error code, should be shown to indicate the
- error compactly for reporting to developers
-
- * hint: String; human-readable Taler error code, should be shown for the
- user to understand the error
-
- * detail: String; optional, extended human-readable text provided to elaborate
- on the error, should be shown to provide additional context
+* ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+* hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+* detail: String; optional, extended human-readable text provided to elaborate
+ on the error, should be shown to provide additional context
+.. _challenger_invalid-request:
invalid-request
---------------
@@ -656,15 +662,14 @@ The request of the client is invalid (HTTP 400 Bad Request).
The template is instantiated using the following information:
- * ec: Integer; numeric Taler error code, should be shown to indicate the
- error compactly for reporting to developers
-
- * hint: String; human-readable Taler error code, should be shown for the
- user to understand the error
-
- * detail: String; optional, extended human-readable text provided to elaborate
- on the error, should be shown to provide additional context
+* ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+* hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+* detail: String; optional, extended human-readable text provided to elaborate
+ on the error, should be shown to provide additional context
+.. _challenger_internal-error:
internal-error
--------------
@@ -673,11 +678,9 @@ The service experienced an internal error (HTTP 500 Internal Server Error).
The template is instantiated using the following information:
- * ec: Integer; numeric Taler error code, should be shown to indicate the
- error compactly for reporting to developers
-
- * hint: String; human-readable Taler error code, should be shown for the
- user to understand the error
-
- * detail: String; optional, extended human-readable text provided to elaborate
- on the error, should be shown to provide additional context
+* ec: Integer; numeric Taler error code, should be shown to indicate the
+ error compactly for reporting to developers
+* hint: String; human-readable Taler error code, should be shown for the
+ user to understand the error
+* detail: String; optional, extended human-readable text provided to elaborate
+ on the error, should be shown to provide additional context
diff --git a/taler-exchange-manual.rst b/taler-exchange-manual.rst
index f0c345c7..91865f24 100644
--- a/taler-exchange-manual.rst
+++ b/taler-exchange-manual.rst
@@ -1948,8 +1948,8 @@ Template Customization
======================
The Exchange comes with various HTML templates that are shown to
-guide users through the KYC process. The Exchange uses `Mustach
-<https://gitlab.com/jbol/mustach>`__ as the templating engine. This section
+guide users through the KYC process. The Exchange uses `C implementation of mustache
+<https://gitlab.com/jobol/mustach>`__ as the templating engine. This section
describes the various templates. In general, the templates must be installed
to the ``share/taler/exchange/templates/`` directory. The file names must be of
the form ``$NAME.$LANG.must`` where ``$NAME`` is the name of the template and
@@ -2319,7 +2319,7 @@ banking protocol standard. It uses a Postgres database to persist data and is
thus much slower than fakebank. If your GNU Taler deployment uses libeufin in
production, it likely makes sense to benchmark with libeufin. When using the
fakebank, ``taler-unified-setup.sh`` must be started with the ``-ns`` options
-(starting libeufin-nexus and libeufin-sandbox) and be told to use the right
+(starting libeufin-nexus and libeufin-bank) and be told to use the right
exchange bank account from the configuration files via ``-u
exchange-account-2``. Note that ``taler-unified-setup.sh`` currently cannot
reset a libeufin database, and also will not run if the database is already
diff --git a/taler-merchant-manual.rst b/taler-merchant-manual.rst
index 6374910a..353885cd 100644
--- a/taler-merchant-manual.rst
+++ b/taler-merchant-manual.rst
@@ -1115,8 +1115,8 @@ Template Customization
The installation process will install various HTML templates to be served to
trigger the wallet interaction. You may change those templates to your own
-design. The templating language used is `Mustach
-<https://gitlab.com/jbol/mustach>`__, and the templates are in the
+design. The templating language used is `C implementation of mustache
+<https://gitlab.com/jobol/mustach>`__, and the templates are in the
``share/taler/merchant/templates/`` directory.
The file names must be of the form ``$NAME.$LANG.must`` where ``$NAME`` is the