summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api-bank-conversion-info.rst4
-rw-r--r--core/api-bank-integration.rst3
-rw-r--r--core/api-bank-wire.rst24
-rw-r--r--core/api-common.rst55
-rw-r--r--core/api-corebank.rst74
-rw-r--r--core/api-exchange.rst863
-rw-r--r--core/api-merchant.rst182
-rw-r--r--core/api-terminal.rst74
-rw-r--r--design-documents/023-taler-kyc.rst632
-rw-r--r--design-documents/046-mumimo-contracts.rst2
-rw-r--r--design-documents/053-wallet-ui.rst16
-rw-r--r--design-documents/054-dynamic-form.rst673
-rw-r--r--frags/installing-ubuntu.rst6
-rw-r--r--images/grafana-postgres-exporter.pngbin244971 -> 0 bytes
-rw-r--r--images/kuma.pngbin244687 -> 0 bytes
-rw-r--r--images/regional-arch.pngbin117525 -> 0 bytes
-rw-r--r--images/taler-monitoring-infrastructure.pngbin85006 -> 0 bytes
-rw-r--r--images/uptime-kuma-edit.pngbin116550 -> 0 bytes
-rw-r--r--images/uptime-kuma-from-grafana.pngbin345702 -> 0 bytes
-rw-r--r--index.rst2
-rw-r--r--libeufin/index.rst1
-rw-r--r--libeufin/regional-automated-manual.rst1
-rw-r--r--libeufin/regional-custom-manual.rst1
-rw-r--r--libeufin/regional-manual-use.rst (renamed from frags/regional-manual-use.rst)19
-rw-r--r--manpages/libeufin-nexus.1.rst22
-rw-r--r--manpages/libeufin-nexus.conf.5.rst58
-rw-r--r--manpages/taler.conf.5.rst189
-rw-r--r--orphaned/python-guidelines.rst (renamed from python-guidelines.rst)0
-rw-r--r--orphaned/qa-0.9.4.rst (renamed from checklists/qa-0.9.4.rst)0
-rw-r--r--screenshots/cta-balance-list-android-1.pngbin0 -> 51463 bytes
l---------screenshots/cta-balance-list-android-latest.png2
-rw-r--r--screenshots/cta-payment-paid-android-1.pngbin0 -> 44605 bytes
l---------screenshots/cta-payment-paid-android-latest.png2
-rw-r--r--screenshots/cta-peer-pull-initiate-android-1.pngbin0 -> 43717 bytes
l---------screenshots/cta-peer-pull-initiate-android-latest.png2
-rw-r--r--screenshots/cta-transaction-list-android-1.pngbin0 -> 86414 bytes
l---------screenshots/cta-transaction-list-android-latest.png2
-rw-r--r--screenshots/cta-url-entry-android-1.pngbin0 -> 23514 bytes
l---------screenshots/cta-url-entry-android-latest.png2
-rw-r--r--screenshots/cta-wire-transfer-android-1.pngbin0 -> 116541 bytes
l---------screenshots/cta-wire-transfer-android-latest.png2
-rw-r--r--screenshots/cta-withdraw-done-android-1.pngbin0 -> 33779 bytes
l---------screenshots/cta-withdraw-done-android-latest.png2
-rw-r--r--screenshots/dynamic-forms.amount.pngbin0 -> 9763 bytes
-rw-r--r--screenshots/dynamic-forms.boolean.pngbin0 -> 7492 bytes
-rw-r--r--screenshots/dynamic-forms.choice.pngbin0 -> 9528 bytes
-rw-r--r--screenshots/dynamic-forms.decorative-elements.pngbin0 -> 22289 bytes
-rw-r--r--screenshots/dynamic-forms.file.pngbin0 -> 51502 bytes
-rw-r--r--screenshots/dynamic-forms.list.pngbin0 -> 17007 bytes
-rw-r--r--screenshots/dynamic-forms.time.pngbin0 -> 10026 bytes
-rw-r--r--system-administration/images/lego-logo.svg1
-rw-r--r--system-administration/index.rst26
-rw-r--r--system-administration/lego-certificates.rst131
-rw-r--r--system-administration/taler-monitoring-infrastructure.rst (renamed from taler-monitoring-infrastructure.rst)29
-rw-r--r--taler-developer-manual.rst8
-rw-r--r--taler-exchange-manual.rst179
-rw-r--r--taler-merchant-manual.rst8
-rw-r--r--taler-merchant-pos-terminal.rst13
-rw-r--r--wallet/wallet-core.md258
59 files changed, 2517 insertions, 1051 deletions
diff --git a/core/api-bank-conversion-info.rst b/core/api-bank-conversion-info.rst
index 322e9403..63856142 100644
--- a/core/api-bank-conversion-info.rst
+++ b/core/api-bank-conversion-info.rst
@@ -108,7 +108,7 @@ is used by wallets for withdrawals that involve a currency conversion.
* ``TALER_EC_GENERIC_PARAMETER_MALFORMED`` : both of the parameters have been provided or one of them is not a valid Taler amount.
* ``TALER_EC_GENERIC_CURRENCY_MISMATCH`` : the parameter is in the wrong currency.
:http:statuscode:`409 Conflict`:
- The amount is too small to be converted, either because it produces produce an amount less than zero, or because the server requires a higher minimum amount than that supplied.
+ The amount is too small to be converted because it produces an amount less than zero.
:http:statuscode:`501 Not implemented`:
This server does not support conversion, client should check config response.
@@ -154,7 +154,7 @@ is used by wallets for withdrawals that involve a currency conversion.
* ``TALER_EC_GENERIC_PARAMETER_MALFORMED`` : both of the parameters have been provided or one of them is not a valid Taler amount.
* ``TALER_EC_GENERIC_CURRENCY_MISMATCH`` : the parameter is in the wrong currency.
:http:statuscode:`409 Conflict`:
- The amount is too small to be converted, either because it produces produce an amount less than zero, or because the server requires a higher minimum amount than that supplied.
+ The amount is too small to be converted because it produces an amount less than zero.
:http:statuscode:`501 Not implemented`:
This server does not support conversion, client should check config response.
diff --git a/core/api-bank-integration.rst b/core/api-bank-integration.rst
index cf41af49..e7db1efc 100644
--- a/core/api-bank-integration.rst
+++ b/core/api-bank-integration.rst
@@ -47,6 +47,7 @@ to tightly integrate with GNU Taler.
// libtool-style representation of the Bank protocol version, see
// https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+
// The format is "current:revision:age".
version: string;
@@ -67,7 +68,7 @@ Withdrawing
-----------
Withdrawals with a Taler-integrated bank are based on withdrawal operations.
-Some user interaction (on the bank's website or a Taler-enabled ATM) creates a
+Some user interaction (on the bank's websitei) creates a
withdrawal operation record in the bank's database. The wallet can use a unique identifier
for the withdrawal operation (the ``WITHDRAWAL_ID``) to interact with the withdrawal operation.
diff --git a/core/api-bank-wire.rst b/core/api-bank-wire.rst
index a76f5195..84184ec9 100644
--- a/core/api-bank-wire.rst
+++ b/core/api-bank-wire.rst
@@ -133,7 +133,8 @@ Making Transactions
// time period a transaction belongs to).
timestamp: Timestamp;
- // Opaque ID of the transaction that the bank has made.
+ // Opaque ID of the wire transfer initiation performed by the bank.
+ // It is different from the /history endpoints row_id.
row_id: SafeUint64;
}
@@ -429,6 +430,25 @@ exposed by bank gateways in production.
// time period a transaction belongs to).
timestamp: Timestamp;
- // Opaque ID of the transaction that the bank has made.
+ // Opaque ID of the wire transfer initiation performed by the bank.
+ // It is different from the /history endpoints row_id.
row_id: SafeUint64;
}
+
+
+Security Considerations
+=======================
+
+For implementors:
+
+* The withdrawal operation ID must contain enough entropy to be unguessable.
+
+Design:
+
+* The user must complete the 2FA step of the withdrawal in the context of their banking
+ app or online banking Website.
+ We explicitly reject any design where the user would have to enter a confirmation code
+ they get from their bank in the context of the wallet, as this would teach and normalize
+ bad security habits.
+
+
diff --git a/core/api-common.rst b/core/api-common.rst
index 521b2fc0..2208eb8d 100644
--- a/core/api-common.rst
+++ b/core/api-common.rst
@@ -255,6 +255,11 @@ hashed data. See `base32`_.
// 32-byte hash code.
type ShortHashCode = string;
+.. ts:def:: AccountAccessToken
+
+ // 32-byte nonce.
+ type AccountAccessToken = string;
+
.. ts:def:: WireSalt
// 16-byte salt.
@@ -758,6 +763,56 @@ denoting microseconds since the UNIX Epoch. ``UINT64_MAX`` represents "never".
uint64_t abs_value_us__; // in network byte order
};
+.. _LegalTrouble:
+
+451 Responses
+^^^^^^^^^^^^^
+
+When KYC operations are required, various endpoints may respond with a
+``451 Unavailable for Legal Reasons`` status code and a `LegitimizationNeededResponse`
+body.
+
+.. ts:def:: LegitimizationNeededResponse
+
+ // Implemented in this style since exchange
+ // protocol **v20**.
+ interface LegitimizationNeededResponse {
+
+ // Numeric `error code <error-codes>` unique to the condition.
+ // Should always be ``TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED``.
+ code: number;
+
+ // Human-readable description of the error, i.e. "missing parameter",
+ // "commitment violation", ... Should give a human-readable hint
+ // about the error's nature. Optional, may change without notice!
+ hint?: string;
+
+ // Hash of the payto:// account URI for which KYC
+ // is required.
+ h_payto: PaytoHash;
+
+ // Public key associated with the account. The client must sign
+ // the initial request for the KYC status using the corresponding
+ // private key. Will be either a reserve public key or a merchant
+ // (instance) public key.
+ //
+ // Absent if no public key is currently associated
+ // with the account and the client MUST thus first
+ // credit the exchange via an inbound wire transfer
+ // to associate a public key with the debited account.
+ account_pub?: EddsaPublicKey;
+
+ // Identifies a set of measures that were triggered and that are
+ // now preventing this operation from proceeding. Gives the
+ // account holder a starting point for understanding why the
+ // transaction was blocked and how to lift it. The account holder
+ // should use the number to check for the account's AML/KYC status
+ // using the ``/kyc-check/$REQUIREMENT_ROW`` endpoint.
+ requirement_row: Integer;
+
+ }
+
+
Cryptographic primitives
^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/core/api-corebank.rst b/core/api-corebank.rst
index 4a0288a4..f9ab7caa 100644
--- a/core/api-corebank.rst
+++ b/core/api-corebank.rst
@@ -188,6 +188,11 @@ Account Management
// Only admin can set this property.
debit_threshold?: Amount;
+ // If present, set a custom minimum cashout amount for this account.
+ // Only admin can set this property
+ // @since v4
+ min_cashout?: Amount;
+
// If present, enables 2FA and set the TAN channel used for challenges
// Only admin can set this property, other user can reconfig their account
// after creation.
@@ -220,6 +225,7 @@ Account Management
* ``TALER_EC_BANK_UNALLOWED_DEBIT`` : admin account does not have sufficient funds to grant bonus.
* ``TALER_EC_BANK_RESERVED_USERNAME_CONFLICT`` : a reserved username was attempted, like ``admin`` or ``bank``
* ``TALER_EC_BANK_NON_ADMIN_PATCH_DEBT_LIMIT`` : a non-admin user has tried to create an account with a customer debt limit.
+ * ``TALER_EC_BANK_NON_ADMIN_SET_MIN_CASHOUT`` : a non-admin user has tried to create an account with a custom min cashout amount.
* ``TALER_EC_BANK_NON_ADMIN_SET_TAN_CHANNEL`` : a non-admin user has tried to create an account with 2fa.
* ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED``: ``tan_channel`` is not supported, check bank config to find supported ones.
* ``TALER_EC_BANK_MISSING_TAN_INFO``: the user did not share any contact data where to send the TAN via ``tan_channel``.
@@ -233,28 +239,6 @@ Account Management
internal_payto_uri: string;
}
-.. _delete-account:
-
-.. http:delete:: /accounts/$USERNAME
-
- Delete the account whose username is ``$USERNAME``. The deletion
- succeeds only if the balance is *zero*. Typically only available to
- the administrator, but can be configured to allow ordinary users too.
-
- **Response:**
-
- :http:statuscode:`202 Accepted`:
- 2FA is required for this operation. This returns the `Challenge` response.
- :http:statuscode:`204 No content`:
- The account was successfully deleted.
- :http:statuscode:`401 Unauthorized`:
- Invalid credentials or missing rights.
- :http:statuscode:`404 Not found`:
- The account pointed by ``$USERNAME`` was not found.
- :http:statuscode:`409 Conflict`:
- * ``TALER_EC_BANK_RESERVED_USERNAME_CONFLICT`` : a reserved username was attempted, like ``admin`` or ``bank``.
- * ``TALER_EC_BANK_ACCOUNT_BALANCE_NOT_ZERO``: the account balance was not zero.
-
.. _account-reconfig:
.. http:patch:: /accounts/$USERNAME
@@ -288,6 +272,11 @@ Account Management
// Only admin can change this property.
debit_threshold?: Amount;
+ // If present, change the custom minimum cashout amount for this account.
+ // Only admin can set this property
+ // @since v4
+ min_cashout?: Amount;
+
// If present, enables 2FA and set the TAN channel used for challenges
tan_channel?: TanChannel;
}
@@ -306,6 +295,7 @@ Account Management
* ``TALER_EC_BANK_NON_ADMIN_PATCH_LEGAL_NAME`` : a non-admin user has tried to change their legal name.
* ``TALER_EC_BANK_NON_ADMIN_PATCH_CASHOUT`` : a non-admin user has tried to change their cashout account.
* ``TALER_EC_BANK_NON_ADMIN_PATCH_DEBT_LIMIT`` : a non-admin user has tried to change their debt limit.
+ * ``TALER_EC_BANK_NON_ADMIN_SET_MIN_CASHOUT`` : a non-admin user has tried to change their custom min cashout amount.
* ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED`` : ``tan_channel`` is not supported, check bank config to find supported ones.
* ``TALER_EC_BANK_MISSING_TAN_INFO`` : the user did not share any contact data where to send the TAN via ``tan_channel``.
@@ -343,6 +333,29 @@ Account Management
* ``TALER_EC_BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD``: a non-admin user has tried to change their password whihout providing the current one.
* ``TALER_EC_BANK_PATCH_BAD_OLD_PASSWORD`` : provided old password does not match current password.
+
+.. _delete-account:
+
+.. http:delete:: /accounts/$USERNAME
+
+ Delete the account whose username is ``$USERNAME``. The deletion
+ succeeds only if the balance is *zero*. Typically only available to
+ the administrator, but can be configured to allow ordinary users too.
+
+ **Response:**
+
+ :http:statuscode:`202 Accepted`:
+ 2FA is required for this operation. This returns the `Challenge` response.
+ :http:statuscode:`204 No content`:
+ The account was successfully deleted.
+ :http:statuscode:`401 Unauthorized`:
+ Invalid credentials or missing rights.
+ :http:statuscode:`404 Not found`:
+ The account pointed by ``$USERNAME`` was not found.
+ :http:statuscode:`409 Conflict`:
+ * ``TALER_EC_BANK_RESERVED_USERNAME_CONFLICT`` : a reserved username was attempted, like ``admin`` or ``bank``.
+ * ``TALER_EC_BANK_ACCOUNT_BALANCE_NOT_ZERO``: the account balance was not zero.
+
.. _account-list:
.. http:get:: /public-accounts
@@ -460,6 +473,11 @@ Account Management
// Number indicating the max debit allowed for the requesting user.
debit_threshold: Amount;
+ // Custom minimum cashout amount for this account.
+ // If null or absent, the global conversion fee is used.
+ // @since v4
+ min_cashout?: Amount;
+
// Is this account visible to anyone?
is_public: boolean;
@@ -513,6 +531,11 @@ Account Management
// Number indicating the max debit allowed for the requesting user.
debit_threshold: Amount;
+ // Custom minimum cashout amount for this account.
+ // If null or absent, the global conversion fee is used.
+ // @since v4
+ min_cashout?: Amount;
+
// Addresses where to send the TAN for transactions.
// Currently only used for cashouts.
// If missing, cashouts will fail.
@@ -883,9 +906,10 @@ Cashouts
The account pointed by ``$USERNAME`` was not found.
:http:statuscode:`409 Conflict`:
* ``TALER_EC_BANK_TRANSFER_REQUEST_UID_REUSED``: an operation with the same ``request_uid`` but different details has been submitted before.
- * ``TALER_EC_BANK_BAD_CONVERSION`` : exchange rate was calculated incorrectly by the client.
- * ``TALER_EC_BANK_UNALLOWED_DEBIT`` : the account does not have sufficient funds.
- * ``TALER_EC_BANK_CONFIRM_INCOMPLETE`` : the user did not share any cashout payto to uri where to wire funds.
+ * ``TALER_EC_BANK_BAD_CONVERSION``: exchange rate was calculated incorrectly by the client.
+ * ``TALER_EC_BANK_BANK_CONVERSION_AMOUNT_TO_SMALL``: the amount of the cashout is too small.
+ * ``TALER_EC_BANK_UNALLOWED_DEBIT``: the account does not have sufficient funds.
+ * ``TALER_EC_BANK_CONFIRM_INCOMPLETE``: the user did not share any cashout payto to uri where to wire funds.
:http:statuscode:`501 Not Implemented`:
* ``TALER_EC_BANK_TAN_CHANNEL_NOT_SUPPORTED``: the chosen ``tan_channel`` is not currently supported.
* This server does not support conversion, client should check config response.
diff --git a/core/api-exchange.rst b/core/api-exchange.rst
index 4c5be000..31d46158 100644
--- a/core/api-exchange.rst
+++ b/core/api-exchange.rst
@@ -62,7 +62,7 @@ possibly by using HTTPS.
as well as the list of possible KYC requirements. This endpoint is largely
for the SPA for AML officers. Merchants should use ``/keys`` which also
contains the protocol version and currency.
- This specification corresponds to ``current`` protocol being **v19**.
+ This specification corresponds to ``current`` protocol being **v20**.
**Response:**
@@ -1323,19 +1323,188 @@ to allow exchange staff to monitor suspicious transactions
and freeze or unfreeze accounts suspected of money laundering.
-.. http:get:: /aml/$OFFICER_PUB/decisions/$STATE
+.. http:get:: /aml/$OFFICER_PUB/measures
- Obtain list of AML decisions (filtered by $STATE). ``$STATE`` must be either ``normal``, ``pending`` or ``frozen``.
+ To enable the AML staff SPA to give AML staff a choice of possible measures, a
+ new endpoint ``/aml/$OFFICER_PUB/measures`` is added that allows the AML SPA
+ to dynamically GET the list of available measures. It returns a list of known
+ KYC checks (by name) with their descriptions and a list of AML programs with
+ information about the required context.
- *Taler-AML-Officer-Signature*: The client must provide Base-32 encoded EdDSA signature with ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that this is merely a simple authentication mechanism, the details of the request are not protected by the signature.
+ This endpoint was introduced in protocol **v20**.
- :query delta: *Optional*. takes value of the form ``N (-N)``, so that at most ``N`` values strictly older (younger) than ``start`` are returned. Defaults to ``-20`` to return the last 20 entries (before ``start``).
- :query start: *Optional*. Row number threshold, see ``delta`` for its interpretation. Defaults to ``INT64_MAX``, namely the biggest row id possible in the database.
+ **Request:**
- **Response**
+ *Taler-AML-Officer-Signature*:
+ The client must provide Base-32 encoded EdDSA signature with
+ ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that
+ this is merely a simple authentication mechanism, the details of the
+ request are not protected by the signature.
+
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ Information about possible measures is returned in a
+ `AvailableMeasureSummary` object.
+
+ **Details:**
+
+ .. ts:def:: AvailableMeasureSummary
+
+ interface AvailableMeasureSummary {
+
+ // Available original measures that can be
+ // triggered directly by default rules.
+ roots: { "$measure_name" : MeasureInformation; };
+
+ // Available AML programs.
+ programs: { "$prog_name" : AmlProgramRequirement; };
+
+ // Available KYC checks.
+ checks: { "$check_name" : KycCheckInformation; };
+
+ }
+
+ .. ts:def:: MeasureInformation
+
+ interface MeasureInformation {
+
+ // Name of a KYC check.
+ check_name: string;
+
+ // Name of an AML program.
+ prog_name: string;
+
+ // Context for the check. Optional.
+ context?: Object;
+
+ }
+
+ .. ts:def:: AmlProgramRequirement
+
+ interface AmlProgramRequirement {
+
+ // Description of what the AML program does.
+ description: string;
+
+ // List of required field names in the context to run this
+ // AML program. SPA must check that the AML staff is providing
+ // adequate CONTEXT when defining a measure using this program.
+ context: string[];
+
+ // List of required attribute names in the
+ // input of this AML program. These attributes
+ // are the minimum that the check must produce
+ // (it may produce more).
+ inputs: string[];
+
+ }
+
+ .. ts:def:: KycCheckInformation
+
+ interface KycCheckInformation {
+
+ // Description of the KYC check. Should be shown
+ // to the AML staff but will also be shown to the
+ // client when they initiate the check in the KYC SPA.
+ description: string;
+ description_i18n: {};
+
+ // Names of the fields that the CONTEXT must provide
+ // as inputs to this check.
+ // SPA must check that the AML staff is providing
+ // adequate CONTEXT when defining a measure using
+ // this check.
+ requires: string[];
+
+ // Names of the attributes the check will output.
+ // SPA must check that the outputs match the
+ // required inputs when combining a KYC check
+ // with an AML program into a measure.
+ outputs: string[];
+
+ // Name of a root measure taken when this check fails.
+ fallback: string;
+ }
+
+.. http:get:: /aml/$OFFICER_PUB/kyc-statistics/$NAME
+
+ Returns the number of KYC events matching the given event type ``$NAME`` in
+ the specified time range. Note that this query can be slow as the
+ statistics are computed on-demand. (This is OK as such requests should be
+ rare.)
+
+ This endpoint was introduced in protocol **v20**.
+
+ **Request:**
+
+ *Taler-AML-Officer-Signature*:
+ The client must provide Base-32 encoded EdDSA signature with
+ ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that this
+ is merely a simple authentication mechanism, the details of the request are
+ not protected by the signature.
+
+ :query start_date=TIMESTAMP:
+ *Optional*. Specifies the date when to
+ start looking (inclusive). If not given, the start time of the
+ exchange operation is used.
+ :query end_date=TIMESTAMP:
+ *Optional*. Specifies the date when to
+ stop looking (exclusive). If not given, the current date is used.
+
+ **Response:**
:http:statuscode:`200 OK`:
- The responds will be an `AmlRecords` message.
+ The responds will be an `EventCounter` message.
+
+ **Details:**
+
+ .. ts:def:: EventCounter
+
+ interface EventCounter {
+ // Number of events of the specified type in
+ // the given range.
+ counter: Integer;
+ }
+
+
+.. http:get:: /aml/$OFFICER_PUB/decisions
+
+ **Request:**
+
+ *Taler-AML-Officer-Signature*:
+ The client must provide Base-32 encoded EdDSA signature with
+ ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that
+ this is merely a simple authentication mechanism, the details of the
+ request are not protected by the signature.
+
+ This endpoint was introduced in this form in protocol **v20**.
+
+ :query limit:
+ *Optional*. takes value of the form ``N (-N)``, so that at
+ most ``N`` values strictly older (younger) than ``start`` are returned.
+ Defaults to ``-20`` to return the last 20 entries (before ``start``).
+ :query offset:
+ *Optional*. Row number threshold, see ``delta`` for its
+ interpretation. Defaults to ``INT64_MAX``, namely the biggest row id
+ possible in the database.
+ :query h_payto:
+ *Optional*. Account selector. All matching accounts are returned if this
+ filter is absent, otherwise only decisions for this account.
+ :query active:
+ *Optional*. If set to yes, only return active decisions, if no only
+ decisions that have been superceeded. Do not give (or use "all") to
+ see all decisions regardless of activity status.
+ :query investigation:
+ *Optional*. If set to yes, only return accounts that are under
+ AML investigation, if no only accounts that are not under investigation.
+ Do not give (or use "all") to see all accounts regardless of
+ investigation status.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The responds will be an `AmlDecisions` message.
:http:statuscode:`204 No content`:
There are no matching AML records.
:http:statuscode:`403 Forbidden`:
@@ -1347,100 +1516,217 @@ and freeze or unfreeze accounts suspected of money laundering.
**Details:**
- .. ts:def:: AmlRecords
+ .. ts:def:: AmlDecisions
- interface AmlRecords {
+ interface AmlDecisions {
- // Array of AML records matching the query.
- records: AmlRecord[];
+ // Array of AML decisions matching the query.
+ records: AmlDecision[];
}
- .. ts:def:: AmlRecord
+ .. ts:def:: AmlDecision
- interface AmlRecord {
+ interface AmlDecision {
// Which payto-address is this record about.
// Identifies a GNU Taler wallet or an affected bank account.
h_payto: PaytoHash;
- // What is the current AML state.
- current_state: Integer;
+ // Row ID of the record. Used to filter by offset.
+ rowid: Integer;
- // Monthly transaction threshold before a review will be triggered
- threshold: Amount;
+ // Justification for the decision.
+ justification: string;
- // RowID of the record.
- rowid: Integer;
+ // When was the decision made?
+ decision_time: Timestamp;
+
+ // Free-form properties about the account.
+ // Can be used to store properties such as PEP,
+ // risk category, type of business, hits on
+ // sanctions lists, etc.
+ properties?: AccountProperties;
+
+ // What are the new rules?
+ limits: LegitimizationRuleSet;
+
+ // True if the account is under investigation by AML staff
+ // after this decision.
+ to_investigate: boolean;
+
+ // True if this is the active decision for the
+ // account.
+ is_active: boolean;
}
+ .. ts:def:: AccountProperties
-.. http:get:: /aml/$OFFICER_PUB/decision/$H_PAYTO
+ // All fields in this object are optional. The actual
+ // properties collected depend fully on the discretion
+ // of the exchange operator;
+ // however, some common fields are standardized
+ // and thus described here.
+ interface AccountProperties {
- Obtain deails about an AML decision.
+ // True if this is a politically exposed account.
+ // Rules for classifying accounts as politically
+ // exposed are country-dependent.
+ pep?: boolean;
- *Taler-AML-Officer-Signature*: The client must provide Base-32 encoded EdDSA signature with ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that this is merely a simple authentication mechanism, the details of the request are not protected by the signature.
+ // True if this is a sanctioned account.
+ // Rules for classifying accounts as sanctioned
+ // are country-dependent.
+ sanctioned?: boolean;
- :query history: *Optional*. If set to yes, we return all historic decisions and not only the last one.
+ // True if this is a high-risk account.
+ // Rules for classifying accounts as at-risk
+ // are exchange operator-dependent.
+ high_risk?: boolean;
- **Response**
+ // Business domain of the account owner.
+ // The list of possible business domains is
+ // operator- or country-dependent.
+ business_domain?: string;
- :http:statuscode:`200 OK`:
- The responds will be an `AmlDecisionDetails` message.
- :http:statuscode:`204 No content`:
- There are no matching AML records for the given payto://-URI.
- :http:statuscode:`403 Forbidden`:
- The signature is invalid.
- :http:statuscode:`404 Not found`:
- The designated AML account is not known.
- :http:statuscode:`409 Conflict`:
- The designated AML account is not enabled.
+ // Is the client's account currently frozen?
+ is_frozen?: boolean;
- **Details:**
+ // Was the client's account reported to the authorities?
+ was_reported?: boolean;
- .. ts:def:: AmlDecisionDetails
+ }
- interface AmlDecisionDetails {
+ .. ts:def:: LegitimizationRuleSet
+
+ interface LegitimizationRuleSet {
+
+ // When does this set of rules expire and
+ // we automatically transition to the successor
+ // measure?
+ expiration_time: Timestamp;
- // Array of AML decisions made for this account. Possibly
- // contains only the most recent decision if "history" was
- // not set to 'true'.
- aml_history: AmlDecisionDetail[];
+ // Name of the measure to apply when the expiration time is
+ // reached. If not set, we refer to the default
+ // set of rules (and the default account state).
+ successor_measure?: string;
+
+ // Legitimization rules that are to be applied
+ // to this account.
+ rules: KycRule[];
+
+ // Custom measures that KYC rules and the
+ // ``successor_measure`` may refer to.
+ custom_measures: { "$measure_name" : MeasureInformation; };
- // Array of KYC attributes obtained for this account.
- kyc_attributes: KycDetail[];
}
- .. ts:def:: AmlDecisionDetail
+ .. ts:def:: KycRule
- interface AmlDecisionDetail {
+ interface KycRule {
- // What was the justification given?
- justification: string;
+ // Type of operation to which the rule applies.
+ operation_type: string;
- // FIXME: review!
- // What is the new AML state.
- new_state: Integer;
+ // The measures will be taken if the given
+ // threshold is crossed over the given timeframe.
+ threshold: Amount;
- // When was this decision made?
- decision_time: Timestamp;
+ // Over which duration should the ``threshold`` be
+ // computed. All amounts of the respective
+ // ``operation_type`` will be added up for this
+ // duration and the sum compared to the ``threshold``.
+ timeframe: RelativeTime;
+
+ // Array of names of measures to apply.
+ // Names listed can be original measures or
+ // custom measures from the `AmlOutcome`.
+ // A special measure "verboten" is used if the
+ // threshold may never be crossed.
+ measures: string[];
+
+ // If multiple rules apply to the same account
+ // at the same time, the number with the highest
+ // rule determines which set of measures will
+ // be activated and thus become visible for the
+ // user.
+ display_priority: Integer;
+
+ // True if the rule (specifically, operation_type,
+ // threshold, timeframe) and the general nature of
+ // the measures (verboten or approval required)
+ // should be exposed to the client.
+ // Defaults to "false" if not set.
+ exposed?: boolean;
+
+ // True if all the measures will eventually need to
+ // be satisfied, false if any of the measures should
+ // do. Primarily used by the SPA to indicate how
+ // the measures apply when showing them to the user;
+ // in the end, AML programs will decide after each
+ // measure what to do next.
+ // Default (if missing) is false.
+ is_and_combinator?: boolean;
+
+ }
+
+.. http:get:: /aml/$OFFICER_PUB/attributes/$H_PAYTO
+
+ Obtain attributes obtained as part of AML/KYC processes for a
+ given account.
+
+ This endpoint was introduced in protocol **v20**.
+
+ **Request:**
+
+ *Taler-AML-Officer-Signature*:
+ The client must provide Base-32 encoded EdDSA signature with
+ ``$OFFICER_PRIV``, affirming the desire to obtain AML data. Note that
+ this is merely a simple authentication mechanism, the details of the
+ request are not protected by the signature.
+
+ :query limit:
+ *Optional*. takes value of the form ``N (-N)``, so that at
+ most ``N`` values strictly older (younger) than ``start`` are returned.
+ Defaults to ``-20`` to return the last 20 entries (before ``start``).
+ :query offset:
+ *Optional*. Row number threshold, see ``delta`` for its
+ interpretation. Defaults to ``INT64_MAX``, namely the biggest row id
+ possible in the database.
+
+ **Response:**
- // What is the new AML decision threshold (in monthly transaction volume)?
- new_threshold: Amount;
+ :http:statuscode:`200 OK`:
+ The responds will be an `KycAttributes` message.
+ :http:statuscode:`204 No content`:
+ There are no matching KYC attributes.
+ :http:statuscode:`403 Forbidden`:
+ The signature is invalid.
+ :http:statuscode:`404 Not found`:
+ The designated AML account is not known.
+ :http:statuscode:`409 Conflict`:
+ The designated AML account is not enabled.
+
+ .. ts:def:: KycAttributes
- // Who made the decision?
- decider_pub: AmlOfficerPublicKeyP;
+ interface KycAttributes {
+
+ // Matching KYC attribute history of the account.
+ details: KycAttributeCollectionEvent[];
}
- .. ts:def:: KycDetail
+ .. ts:def:: KycAttributeCollectionEvent
- interface KycDetail {
+ interface KycAttributeCollectionEvent {
- // Name of the configuration section that specifies the provider
- // which was used to collect the KYC details
- // FIXME: review!
- provider_section: string;
+ // Row ID of the record. Used to filter by offset.
+ rowid: Integer;
+
+ // Name of the provider
+ // which was used to collect the attributes. NULL if they were
+ // just uploaded via a form by the account owner.
+ provider_name?: string;
// The collected KYC data. NULL if the attribute data could not
// be decrypted (internal error of the exchange, likely the
@@ -1450,9 +1736,6 @@ and freeze or unfreeze accounts suspected of money laundering.
// Time when the KYC data was collected
collection_time: Timestamp;
- // Time when the validity of the KYC data will expire
- expiration_time: Timestamp;
-
}
@@ -1487,17 +1770,17 @@ and freeze or unfreeze accounts suspected of money laundering.
// Human-readable justification for the decision.
justification: string;
- // At what monthly transaction volume should the
- // decision be automatically reviewed?
- new_threshold: Amount;
-
// Which payto-address is the decision about?
// Identifies a GNU Taler wallet or an affected bank account.
h_payto: PaytoHash;
- // What is the new AML state (e.g. frozen, unfrozen, etc.)
- // Numerical values are defined in `AmlDecisionState`.
- new_state: Integer;
+ // What are the new rules?
+ // New since protocol **v20**.
+ new_rules: LegitimizationRuleSet;
+
+ // True if the account should remain under investigation by AML staff.
+ // New since protocol **v20**.
+ keep_investigating: boolean;
// Signature by the AML officer over a `TALER_AmlDecisionPS`.
// Must have purpose ``TALER_SIGNATURE_MASTER_AML_KEY``.
@@ -1506,9 +1789,6 @@ and freeze or unfreeze accounts suspected of money laundering.
// When was the decision made?
decision_time: Timestamp;
- // Optional argument to impose new KYC requirements
- // that the customer has to satisfy to unblock transactions.
- kyc_requirements?: string[];
}
@@ -1769,7 +2049,7 @@ Batch Withdraw
The user should be redirected to the provided location to perform
the required KYC checks to open the account before withdrawing.
Afterwards, the request should be repeated.
- The response will be an `KycNeededRedirect` object.
+ The response will be an `LegitimizationNeededResponse` object.
Implementation note: internally, we need to
distinguish between upgrading the reserve to an
@@ -1857,29 +2137,6 @@ Batch Withdraw
}
- .. ts:def:: KycNeededRedirect
-
- interface KycNeededRedirect {
-
- // Numeric `error code <error-codes>` unique to the condition.
- // Should always be ``TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED``.
- code: number;
-
- // Human-readable description of the error, i.e. "missing parameter", "commitment violation", ...
- // Should give a human-readable hint about the error's nature. Optional, may change without notice!
- hint?: string;
-
- // Hash of the payto:// account URI that identifies
- // the account which is being KYCed.
- h_payto: PaytoHash;
-
- // Legitimization target that the merchant should
- // use to check for its KYC status using
- // the ``/kyc-check/$REQUIREMENT_ROW/...`` endpoint.
- requirement_row: Integer;
-
- }
-
.. ts:def:: WithdrawError
interface WithdrawError {
@@ -1986,7 +2243,7 @@ If so, the exchange will blindly sign ``n`` undisclosed coins from the request.
The user should be redirected to the provided location to perform
the required KYC checks to open the account before withdrawing.
Afterwards, the request should be repeated.
- The response will be an `KycNeededRedirect` object.
+ The response will be an `LegitimizationNeededResponse` object.
.. ts:def:: AgeWithdrawRequest
@@ -3970,6 +4227,7 @@ typically also view the balance.)
// Current AML state for the target account. Non-zero
// values indicate that the transfer is blocked due to
// AML enforcement.
+ // Removed in protocol **v20**.
aml_decision: Integer;
// True if the KYC check for the merchant has been
@@ -4465,7 +4723,7 @@ Wallet-to-wallet transfers
:http:statuscode:`451 Unavailable For Legal Reasons`:
This account has not yet passed the KYC checks.
The client must pass KYC checks before proceeding with the merge.
- The response will be an `KycNeededRedirect` object.
+ The response will be an `LegitimizationNeededResponse` object.
**Details:**
@@ -4576,7 +4834,7 @@ Wallet-to-wallet transfers
:http:statuscode:`451 Unavailable For Legal Reasons`:
This account has not yet passed the KYC checks.
The client must pass KYC checks before proceeding with the merge.
- The response will be an `KycNeededRedirect` object.
+ The response will be an `LegitimizationNeededResponse` object.
**Details:**
@@ -4869,6 +5127,17 @@ regulatory compliance.
.. http:post:: /kyc-wallet
+ The ``/wallet-kyc`` POST endpoint allows a wallet to notify an exchange if
+ it will cross a balance threshold. Here, the ``balance`` specified should be
+ the threshold (from the ``wallet_balance_limit_without_kyc`` array) that the
+ wallet would cross, and *not* the *exact* balance of the wallet. The exchange
+ will respond with a wire target UUID. The wallet can then use this UUID to
+ being the KYC process at ``/kyc-check/``. The wallet must only proceed to
+ obtain funds exceeding the threshold after the KYC process has concluded.
+ While wallets could be "hacked" to bypass this measure (we cannot
+ cryptographically enforce this), such modifications are a terms of service
+ violation which may have legal consequences for the user.
+
Setup KYC identification for a wallet. Returns the KYC UUID.
This endpoint is used by compliant Taler wallets when they
are about to hit the balance threshold and thus need to have
@@ -4892,7 +5161,7 @@ regulatory compliance.
This response comes with a standard `ErrorDetail` response.
:http:statuscode:`451 Unavailable for Legal Reasons`:
The wallet must undergo a KYC check. A KYC ID was created.
- The response will be a `WalletKycUuid` object.
+ The response will be a `LegitimizationNeededResponse` object (changed in protocol **v20**).
**Details:**
@@ -4915,73 +5184,74 @@ regulatory compliance.
reserve_pub: EddsaPublicKey;
}
- .. ts:def:: WalletKycUuid
+.. http:get:: /kyc-check/$REQUIREMENT_ROW
- interface WalletKycUuid {
+ Checks the KYC status of a particular payment target and possibly begins a
+ KYC process by allowing the customer to choose the next KYC measure to
+ satisfy. This endpoint is typically used by wallets or merchants that
+ have been told that a transaction is not happening because it triggered
+ some KYC/AML measure and now want to check how the KYC/AML
+ requirement could be fulfilled (or whether it already has been
+ statisfied and the operation can now proceed). Long-polling may be used
+ to instantly observe a change in the KYC requirement status.
- // UUID that the wallet should use when initiating
- // the KYC check.
- requirement_row: number;
+ The requirement row of the ``/kyc-check/`` endpoint encodes the
+ legitimization measure's serial number. It is returned in
+ `LegitimizationNeededResponse` responses via the ``requirement_row`` field.
- // Hash of the payto:// account URI for the wallet.
- h_payto: PaytoHash;
-
- }
+ Given a valid pair of requirement row and account owner signature, the
+ ``/kyc-check/`` endpoint returns either just the KYC status or redirects the
+ client (202) to the next required stage of the KYC process. The redirection
+ must be for an HTTP(S) endpoint to be triggered via a simple HTTP GET. It
+ must always be the same endpoint for the same client, as the wallet/merchant
+ backend are not required to check for changes to this endpoint. Clients
+ that received a 202 status code may repeat the request and use long-polling
+ to detect a change of the HTTP status.
+ This endpoint exists in this specific form only since protocol **v20**.
-.. http:get:: /kyc-check/$REQUIREMENT_ROW/$H_PAYTO/$USERTYPE
-
- Checks the KYC status of a particular payment target and possibly begins the
- KYC process. This endpoint is used by wallets or merchants that have been
- told about a KYC requirement and now want to check if the KYC requirement
- has been fulfilled. Long-polling may be used to instantly observe a change
- in the KYC requirement status.
+ **Request:**
- Returns the current KYC status of the requirement process and, if negative,
- returns the URL where the KYC process can be initiated. The
- ``$REQUIREMENT_ROW`` must have been returned previously from an exchange API
- endpoint that determined that KYC was needed. The ``$H_PATYO`` must be the
- hash of the "payto://" URI of the payment target. The ``$USERTYPE`` states
- whether the entity to perform the KYC is an "individual" or a "business".
+ *Account-Owner-Signature*:
- **Request:**
+ The client must provide Base-32 encoded EdDSA signature with
+ ``$ACCOUNT_PRIV``, affirming the desire to obtain KYC data. Note that
+ this is merely a simple authentication mechanism, the details of the
+ request are not protected by the signature. The ``$ACCOUNT_PRIV`` is
+ either the (wallet long-term) reserve private key or the merchant instance
+ private key.
:query timeout_ms=NUMBER: *Optional.* If specified, the exchange will
- wait up to ``timeout_ms`` milliseconds if the payment target
- is currently not legitimized. Ignored if the payment target
- is already legitimized. Note that the legitimization would be
- triggered by another request to the same endpoint with a valid
- ``token``.
+ wait up to ``timeout_ms`` milliseconds if the requirement continues
+ to be mandatory provisioning of KYC data by the client.
+ Ignored if the HTTP status code is already ``200 Ok``. Note that
+ clients cannot long-poll for AML staff actions, so status information
+ about an account being under AML review needs to be requested
+ periodically.
**Response:**
:http:statuscode:`200 Ok`:
- The KYC operation succeeded, the exchange confirms that the
- payment target already authorized to transact.
- The response will be an `AccountKycStatus` object.
+ No mandatory KYC actions are required by the client at this time.
+ The client *may* still visit the KYC URL to initiate voluntary checks.
+ The response will be an `AccountKycStatus` object which specifies
+ restrictions that currently apply to the account. If the
+ client attempts to exceed *soft* limits, the status may change
+ to a ``202 Accepted``. Hard limits cannot be lifted by passing KYC checks.
:http:statuscode:`202 Accepted`:
- The user should be redirected to the provided location to perform
+ The account holder performed an operation that would have crossed
+ *soft* limits and must be redirected to the provided location to perform
the required KYC checks to satisfy the legal requirements. Afterwards, the
``/kyc-check/`` request should be repeated to check whether the
user has completed the process.
- The response will be an `AccountKycRedirect` object.
+ The response will be an `AccountKycStatus` object.
:http:statuscode:`204 No content`:
The exchange is not configured to perform KYC and thus
the legal requirements are already satisfied.
- :http:statuscode:`402 Payment Required`:
- The client must pay the KYC fee for the KYC process.
- **This is currently not implemented, see #7365.**
:http:statuscode:`403 Forbidden`:
- The provided hash does not match the payment target.
+ The provided signature is not acceptable for the requirement row.
:http:statuscode:`404 Not found`:
- The payment target is unknown.
- :http:statuscode:`451 Unavailable for Legal Reasons`:
- The transaction cannot be completed due to AML rules.
- Thus, the operation is currently not stuck on KYC, but
- on exchange staff performing their AML review. The user
- should be told to wait and/or contact the exchange operator
- if the situation persists.
- The response will be a `AccountAmlBlocked` object.
+ The requirement row is unknown.
**Details:**
@@ -4989,75 +5259,274 @@ regulatory compliance.
interface AccountKycStatus {
- // Details about the KYC check that the user
- // passed.
- kyc_details: KycDetails;
+ // Current AML state for the target account. True if
+ // operations are not happening due to staff processing
+ // paperwork *or* due to legal requirements (so the
+ // client cannot do anything but wait).
+ //
+ // Note that not every AML staff action may be legally
+ // exposed to the client, so this is merely a hint that
+ // a client should be told that AML staff is currently
+ // reviewing the account. AML staff *may* review
+ // accounts without this flag being set!
+ aml_review: boolean;
+
+ // Access token needed to construct the ``/kyc-spa/``
+ // URL that the user should open in a browser to
+ // proceed with the KYC process (optional if the status
+ // type is ``200 Ok``, mandatory if the HTTP status
+ // is ``202 Accepted``).
+ access_token: AccountAccessToken;
+
+ // Array with limitations that currently apply to this
+ // account and that may be increased or lifted if the
+ // KYC check is passed.
+ // Note that additional limits *may* exist and not be
+ // communicated to the client. If such limits are
+ // reached, this *may* be indicated by the account
+ // going into ``aml_review`` state. However, it is
+ // also possible that the exchange may legally have
+ // to deny operations without being allowed to provide
+ // any justification.
+ // The limits should be used by the client to
+ // possibly structure their operations (e.g. withdraw
+ // what is possible below the limit, ask the user to
+ // pass KYC checks or withdraw the rest after the time
+ // limit is passed, warn the user to not withdraw too
+ // much or even prevent the user from generating a
+ // request that would cause it to exceed hard limits).
+ limits?: AccountLimit[];
+
+ }
+
+ .. ts:def:: AccountLimit
+
+ interface AccountLimit {
+
+ // Operation that is limited.
+ // Must be one of "WITHDRAW", "DEPOSIT", "P2P-RECEIVE"
+ // or "WALLET-BALANCE".
+ operation_type: string;
+
+ // Timeframe during which the limit applies.
+ timeframe: RelativeTime;
+
+ // Maximum amount allowed during the given timeframe.
+ // Zero if the operation is simply forbidden.
+ threshold: Amount;
- // Current time of the exchange, used as part of
- // what the exchange signs over.
- now: Timestamp;
+ // True if this is a soft limit that could be raised
+ // by passing KYC checks. Clients *may* deliberately
+ // try to cross limits and trigger measures resulting
+ // in 451 responses to begin KYC processes.
+ // Clients that are aware of hard limits *should*
+ // inform users about the hard limit and prevent flows
+ // in the UI that would cause violations of hard limits.
+ soft_limit: boolean;
+ }
+
+.. http:get:: /kyc-spa/$ACCESS_TOKEN
+.. http:get:: /kyc-spa/$FILENAME
+
+ A set of ``/kyc-spa/$ACCESS_TOKEN`` GET endpoints is created per account
+ hash that serves the KYC SPA. This is where the ``/kyc-check/`` endpoint
+ will in principle redirect clients. The KYC SPA will use the
+ ``$ACCESS_TOKEN`` of its URL to initialize itself via the
+ ``/kyc-info/$ACCESS_TOKEN`` endpoint family. The KYC SPA may download
+ additional resources via ``/kyc-spa/$FILENAME``. The filenames must not
+ match base32-encoded 256-bit values.
+
+ This endpoint was introduced in protocol **v20**.
+
+
+.. http:get:: /kyc-info/$ACCESS_TOKEN
+
+ The ``/kyc-info/$ACCESS_TOKEN`` endpoints are created per client
+ account hash (but access controlled via a unique target token)
+ to return information about the state of the KYC or AML process
+ to the KYC SPA. The SPA uses this information to show the user an
+ appropriate dialog. The SPA should also long-poll this endpoint for changes
+ to the AML/KYC state. Note that this is a client-facing endpoint, so it will
+ only provide a restricted amount of information to the customer (as some
+ laws may forbid us to inform particular customers about their true status).
+ The endpoint will typically inform the SPA about possible choices to
+ proceed, such as directly uploading files, contacting AML staff, or
+ proceeding with a particular KYC process at an external provider (such as
+ Challenger). If the user chooses to initate a KYC process at an external
+ provider, the SPA must request the respective process to be set-up by the
+ exchange via the ``/kyc-start/`` endpoint.
+
+ This endpoint was introduced in protocol **v20**.
- // EdDSA signature of the exchange affirming the account
- // is KYC'ed, must be of purpose
- // ``TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS``
- // and over ``TALER_AccountSetupStatusSignaturePS``.
- exchange_sig: EddsaSignature;
+ **Request:**
- // public key used to create the signature.
- exchange_pub: EddsaPublicKey;
+ *If-None-Match*:
+ The client MAY provide an ``If-None-Match`` header with an ETag.
- // Current AML state for the target account. Non-zero
- // values indicate that the transfer is blocked due to
- // AML enforcement.
- aml_status: Integer;
+ :query timeout_ms=MILLISECONDS:
+ *Optional.* If specified, the exchange will wait up to MILLISECONDS for
+ a change to a more recent legitimization measure before returning a 304
+ Not Modified status.
+ **Response:**
+
+ *Etag*: Will be set to the serial ID of the measure. Used for long-polling (only for 200 OK responses).
+
+ :http:statuscode:`200 OK`:
+ The body is a `KycProcessClientInformation`.
+ :http:statuscode:`204 No Content`:
+ There are no open KYC requirements or possible voluntary checks
+ the client might perform.
+ :http:statuscode:`304 Not Modified`:
+ The KYC requirements did not change.
+
+
+ **Details:**
+
+ .. ts:def:: KycProcessClientInformation
+
+ interface KycProcessClientInformation {
+
+ // List of requirements.
+ requirements?: { name : KycRequirementInformation};
+
+ // True if the client is expected to eventually satisfy all requirements.
+ // Default (if missing) is false.
+ is_and_combinator?: boolean
+
+ // List of available voluntary checks the client could pay for.
+ // Since **vATTEST**.
+ voluntary_checks?: { name : KycCheckInformation};
}
- .. ts:def:: AccountKycRedirect
+ .. ts:def:: KycRequirementInformation
- interface AccountKycRedirect {
+ interface KycRequirementInformation {
- // URL that the user should open in a browser to
- // proceed with the KYC process.
- kyc_url: string;
+ // Which form should be used? Common values include "INFO"
+ // (to just show the descriptions but allow no action),
+ // "LINK" (to enable the user to obtain a link via
+ // ``/kyc-start/``) or any build-in form name supported
+ // by the SPA.
+ form: string;
- // Current AML state for the target account. Non-zero
- // values indicate that the transfer is blocked due to
- // AML enforcement.
- aml_status: Integer;
+ // English description of the requirement.
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized
+ // description texts.
+ description_i18n ?: { [lang_tag: string]: string };
+
+ // ID of the requirement, useful to construct the
+ // ``/kyc-upload/$ID`` or ``/kyc-start/$ID`` endpoint URLs.
+ // Present if and only if "form" is not "INFO". The
+ // ``$ID`` value may itself contain ``/`` or ``?`` and
+ // basically encode any URL path (and optional arguments).
+ id?: string;
}
- .. ts:def:: AccountAmlBlocked
+ .. ts:def:: KycCheckInformation
- interface AccountAmlBlocked {
+ // Since **vATTEST**.
+ interface KycCheckInformation {
- // Current AML state for the target account. Non-zero
- // values indicate that the transfer is blocked due to
- // AML enforcement.
- aml_status: Integer;
+ // English description of the check.
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized
+ // description texts.
+ description_i18n ?: { [lang_tag: string]: string };
+ // FIXME: is the above in any way sufficient
+ // to begin the check? Do we not need at least
+ // something more??!?
}
- .. ts:def:: KycDetails
- // Object that specifies which KYC checks are satisfied.
- interface KycDetails {
+.. http:post:: /kyc-upload/$ID
+
+ The ``/kyc-upload/$ID`` POST endpoint allows the SPA to upload
+ client-provided evidence. The ``$ID`` will be provided as part of the
+ ``/kyc-info`` body. This is for checks of type ``FORM``. In practice,
+ ``$ID`` will encode both the ``$ACCESS_TOKEN`` and the index of the selected
+ measure (but this should be irrelevant for the client).
+
+ This endpoint was introduced in protocol **v20**.
- // Keys are the names of the check(s).
- // The values are for now always empty objects.
+ **Request:**
+
+ Basically oriented along the possible formats of a HTTP form being
+ POSTed. Details will depend on the form. The server will try to decode the
+ uploaded body from whatever format it is provided in.
+
+ **Response:**
+
+ :http:statuscode:`204 No Content`:
+ The information was successfully uploaded. The SPA should fetch
+ an updated ``/kyc-info/``.
+ :http:statuscode:`404 Not Found`:
+ The ``$ID`` is unknown to the exchange.
+ :http:statuscode:`409 Conflict`:
+ The upload conflicts with a previous upload.
+ :http:statuscode:`413 Request Entity Too Large`:
+ The body is too large.
+
+.. http:post:: /kyc-start/$ID
+
+ The ``/kyc-start/$ID`` POST endpoint allows the SPA to set up a new external
+ KYC process. It will return the URL that the client must GET to begin the
+ KYC process. The SPA should probably open this URL in a new window or tab.
+ The ``$ID`` will be provided as part of the ``/kyc-info`` body. In
+ practice, ``$ID`` will encode both the ``$ACCESS_TOKEN`` and the index of
+ the selected measure (but this should be irrelevant for the client).
+
+ **Request:**
+
+ Use empty JSON body for now.
+ **Response:**
+
+ :http:statuscode:`200 Ok`:
+ The KYC process was successfully initiated. The URL is in a
+ `KycProcessStartInformation` object.
+ :http:statuscode:`404 Not Found`:
+ The ``$ID`` is unknown to the exchange.
+
+ **Details:**
+
+ .. ts:def:: KycProcessStartInformation
+
+ interface KycProcessStartInformation {
+
+ // URL to open.
+ redirect_url: string;
}
-.. http:get:: /kyc-proof/$PROVIDER_SECTION?state=$H_PAYTO
+ .. note::
+
+ As this endpoint is involved in every KYC check at the beginning, this
+ is also the place where we could integrate the payment process for the KYC fee
+ in the future (since **vATTEST**).
+
+.. http:get:: /kyc-proof/$PROVIDER_NAME?state=$H_PAYTO
+
+ Upon completion of the process at the external KYC provider, the provider
+ must redirect the client (browser) to trigger a GET request to a new
+ ``/kyc-proof/$H_PAYTO/$PROVIDER_NAME`` endpoint. Once this endpoint is
+ triggered, the exchange will pass the received arguments to the respective
+ logic plugin. The logic plugin will then (asynchronously) update the KYC
+ status of the user. The logic plugin should redirect the user to the KYC
+ SPA. This endpoint deliberately does not use the ``$ACCESS_TOKEN`` as the
+ external KYC provider should not learn that token.
- Endpoint accessed from the user's browser at the *end* of a
+ This endpoint is thus accessed from the user's browser at the *end* of a
KYC process, possibly providing the exchange with additional
credentials to obtain the results of the KYC process.
Specifically, the URL arguments should provide
information to the exchange that allows it to verify that the
user has completed the KYC process. The details depend on
- the logic, which is selected by the "$PROVIDER_SECTION".
+ the logic, which is selected by the "$PROVIDER_NAME".
While this is a GET (and thus safe, and idempotent), the operation
may actually trigger significant changes in the exchange's state.
@@ -5071,8 +5540,10 @@ regulatory compliance.
If the KYC plugin logic is OAuth 2.0, the query parameters are:
- :query code=CODE: OAuth 2.0 code argument.
- :query state=STATE: OAuth 2.0 state argument with the H_PAYTO.
+ :query code=CODE:
+ OAuth 2.0 code argument.
+ :query state=STATE:
+ OAuth 2.0 state argument with the H_PAYTO.
.. note::
@@ -5102,8 +5573,8 @@ regulatory compliance.
service within a reasonable time period.
-.. http:get:: /kyc-webhook/$PROVIDER_SECTION/*
-.. http:post:: /kyc-webhook/$PROVIDER_SECTION/*
+.. http:get:: /kyc-webhook/$PROVIDER_NAME/*
+.. http:post:: /kyc-webhook/$PROVIDER_NAME/*
.. http:get:: /kyc-webhook/$LOGIC/*
.. http:post:: /kyc-webhook/$LOGIC/*
@@ -5111,7 +5582,7 @@ regulatory compliance.
payment target. They provide information to the KYC logic of the exchange
that allows it to verify that the user has completed the KYC process. May
be a GET or a POST request, depending on the specific "$LOGIC" and/or the
- "$PROVIDER_SECTION".
+ "$PROVIDER_NAME".
**Request:**
@@ -5176,7 +5647,7 @@ designated account.
:http:statuscode:`451 Unavailable For Legal Reasons`:
This account has not yet passed the KYC checks.
The client must pass KYC checks before the reserve can be opened.
- The response will be an `KycNeededRedirect` object.
+ The response will be an `LegitimizationNeededResponse` object.
**Details:**
@@ -5392,7 +5863,7 @@ designated account.
This account has not yet passed the KYC checks, hence wiring
funds to a non-origin account is not allowed.
The client must pass KYC checks before the reserve can be opened.
- The response will be an `KycNeededRedirect` object.
+ The response will be an `LegitimizationNeededResponse` object.
**Details:**
diff --git a/core/api-merchant.rst b/core/api-merchant.rst
index f3801cbf..0e45cbad 100644
--- a/core/api-merchant.rst
+++ b/core/api-merchant.rst
@@ -123,7 +123,7 @@ such as the implemented version of the protocol and the currency used.
.. http:get:: /config
Return the protocol version and currency supported by this merchant backend.
- This specification corresponds to ``current`` protocol being version **v14**.
+ This specification corresponds to ``current`` protocol being version **v15**.
**Response:**
@@ -342,6 +342,11 @@ Making the payment
// payment.
pos_confirmation?: string;
+ // Signed tokens. Returned in the same order as the
+ // token envelopes were provided in the request.
+ // @since protocol **vSUBSCRIBE**
+ token_sigs?: SignedTokenEnvelope[];
+
}
.. ts:def:: PayRequest
@@ -350,11 +355,6 @@ Making the payment
// The coins used to make the payment.
coins: CoinPaySig[];
- // 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?: TokenUseSig[];
@@ -365,7 +365,7 @@ Making the payment
tokens_evs?: TokenEnvelope[];
// Custom inputs from the wallet for the contract.
- wallet_data?: Object;
+ wallet_data?: PayWalletData;
// The session for which the payment is made (or replayed).
// Only set for session-based payments.
@@ -373,6 +373,59 @@ Making the payment
}
+ .. ts:def:: SignedTokenEnvelope
+
+ interface SignedTokenEnvelope {
+
+ // Blind signature made by the merchant.
+ blind_sig: TokenIssueBlindSig;
+
+ // Hash of the token issue public key.
+ h_issue: HashCode;
+
+ }
+
+ .. ts:def:: TokenIssueBlindSig
+
+ type TokenIssueBlindSig = RSATokenIssueBlindSig | CSTokenIssueBlindSig;
+
+ .. ts:def:: RSATokenIssueBlindSig
+
+ interface RSATokenIssueBlindSig {
+ cipher: "RSA";
+
+ // (blinded) RSA signature
+ blinded_rsa_signature: BlindedRsaSignature;
+ }
+
+ .. ts:def:: CSTokenIssueBlindSig
+
+ interface CSTokenIssueBlindSig {
+ type: "CS";
+
+ // Signer chosen bit value, 0 or 1, used
+ // in Clause Blind Schnorr to make the
+ // ROS problem harder.
+ b: Integer;
+
+ // Blinded scalar calculated from c_b.
+ s: Cs25519Scalar;
+
+ }
+
+ .. ts:def:: PayWalletData
+
+ interface PayWalletData {
+ // Index of the selected choice within the ``choices`` array of
+ // the contract terms.
+ // @since protocol **vSUBSCRIBE**
+ choice_index?: Integer;
+
+ // Output commitment. Hash over output token envelopes.
+ // @since protocol **vSUBSCRIBE**
+ h_outputs?: HashCode;
+ }
+
.. ts:def:: CoinPaySig
export interface CoinPaySig {
@@ -418,27 +471,41 @@ Making the payment
interface TokenUseSig {
- // Signature on ``TALER_DepositRequestPS`` with the token use key of the
- // token being used in this request.
+ // Signature on ``TALER_TokenUseRequestPS`` with the token use key of
+ // the token being used in this request.
token_sig: EddsaSignature;
// Token use public key.
token_pub: EddsaPublicKey;
- // Unblinded signature made by the token issue public key of the merchant.
+ // Unblinded signature on ``TALER_TokenIssueRequestPS`` with the token
+ // issue public key of the merchant.
ub_sig: UnblindedSignature;
- // The hash of the token issue public key associated with this token.
+ // The hash of the token issue public key of the token being using
+ // in this request.
h_issue: HashCode;
}
.. ts:def:: TokenEnvelope
+ interface TokenEnvelope {
+
+ // Blinded token use public key.
+ token_ev: BlindedTokenEnvelope;
+
+ // Hash of the token issue public key.
+ h_issue: HashCode;
+
+ }
+
+ .. ts:def:: BlindedTokenEnvelope
+
// This type depends on the cipher used to sign token families. This is
// configured by the merchant and defined for each token family in the
// contract terms.
- type TokenEnvelope = RSATokenEnvelope | CSTokenEnvelope;
+ type BlindedTokenEnvelope = RSATokenEnvelope | CSTokenEnvelope;
.. ts:def:: RSATokenEnvelope
@@ -1851,6 +1918,7 @@ Inspecting inventory
image: ImageDataUrl;
// A list of taxes paid by the merchant for one unit of this product.
+ // Optional since **v15**.
taxes: Tax[];
// Number of units of the product in stock in sum in total,
@@ -1866,7 +1934,8 @@ Inspecting inventory
total_lost: Integer;
// Identifies where the product is in stock.
- address: Location;
+ // Optional since **v15**.
+ address?: Location;
// Identifies when we expect the next restocking to happen.
next_restock?: Timestamp;
@@ -1876,6 +1945,93 @@ Inspecting inventory
}
+.. http:get:: [/instances/$INSTANCE]/private/pos
+
+ This is used to return the point-of-sale (POS) configuration with full details on all items in the inventory.
+
+ Endpoint was introduced in protocol **v15**.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The backend has successfully returned the inventory. Returns
+ a `FullInventoryDetailsResponse`.
+ :http:statuscode:`404 Not found`:
+ The backend has does not know about the instance.
+
+ .. ts:def:: FullInventoryDetailsResponse
+
+ interface FullInventoryDetailsResponse {
+
+ // List of products that are present in the inventory.
+ products: MerchantPosProductDetail[];
+
+ // List of categories in the inventory.
+ categories: MerchantCategory[];
+
+ }
+
+ .. ts:def:: MerchantPosProductDetail
+
+ interface MerchantPosProductDetail {
+
+ // A unique numeric ID of the product
+ product_serial: number;
+
+ // A merchant-internal unique identifier for the product
+ product_id?: string;
+
+ // A list of category IDs this product belongs to.
+ // Typically, a product only belongs to one category, but more than one is supported.
+ categories: number[];
+
+ // Human-readable product description.
+ description: string;
+
+ // Map from IETF BCP 47 language tags to localized descriptions.
+ description_i18n: { [lang_tag: string]: string };
+
+ // Unit in which the product is measured (liters, kilograms, packages, etc.).
+ unit: string;
+
+ // The price for one ``unit`` of the product. Zero is used
+ // to imply that this product is not sold separately, or
+ // that the price is not fixed, and must be supplied by the
+ // front-end. If non-zero, this price MUST include applicable
+ // taxes.
+ price: Amount;
+
+ // An optional base64-encoded product image.
+ image?: ImageDataUrl;
+
+ // A list of taxes paid by the merchant for one unit of this product.
+ taxes?: Tax[];
+
+ // Number of units of the product in stock in sum in total,
+ // including all existing sales ever. Given in product-specific
+ // units.
+ // Optional, if missing treat as "infinite".
+ total_stock?: Integer;
+
+ // Minimum age buyer must have (in years).
+ minimum_age?: Integer;
+
+ }
+
+ .. ts:def:: MerchantCategory
+
+ interface MerchantCategory {
+ // A unique numeric ID of the category
+ id: number;
+
+ // The name of the category. This will be shown to users and used in the order summary.
+ name: string;
+
+ // Map from IETF BCP 47 language tags to localized names
+ name_i18n?: { [lang_tag: string]: string };
+ }
+
+
Reserving inventory
-------------------
diff --git a/core/api-terminal.rst b/core/api-terminal.rst
index be2e81aa..91d9b7e6 100644
--- a/core/api-terminal.rst
+++ b/core/api-terminal.rst
@@ -42,8 +42,7 @@ payment service (or a bank) to realize the service.
Authentication
--------------
-Most requests require the client to authenticate using a bearer token.
-The bearer token is expected to be part of the service configuration.
+Terminals must authenticate against all terminal API using basic auth according to `HTTP basic auth <https://tools.ietf.org/html/rfc7617>`_.
Config
@@ -75,8 +74,9 @@ Config
// Terminal provider display name to be used in user interfaces.
provider_name: string;
- // Currency supported by this terminal.
- // FIXME: needed?
+ // The currency supported by this Terminal-API
+ // must be the same as the currency specified
+ // in the currency field of the wire gateway config
currency: string;
// Wire transfer type supported by the terminal.
@@ -198,18 +198,13 @@ Config
// as we may not know it at this time.
provider_transaction_id?: string;
- // An identifier, which identifies the device
- // processing the payment for the withdrawal
- // triggering the confirmation (e.g. Terminal
- // or ATM). This is useful to internally link
- // the withdrawal to a terminal owned by a
- // specific provider.
- terminal_id?: string;
-
- // The non-Taler card fees the customer will have
+ // The non-Taler fees the customer will have
// to pay to the service provider
// they are using to make this withdrawal.
- card_fees: Amount;
+ // If the fees cannot be precalculated,
+ // they can be specified in the /withdrawals/$WITHDRAWAL_ID/check
+ // request after the transaction was executed.
+ terminal_fees?: Amount;
// Unique request ID to make retried requests idempotent.
request_uid: string;
@@ -222,7 +217,6 @@ Config
// may wish to use in this operation. May only be
// present if ``user_uuid`` is also given.
lock?: string;
-
}
.. ts:def:: TerminalWithdrawalSetupResponse
@@ -231,11 +225,10 @@ Config
// ID identifying the withdrawal operation being created.
withdrawal_id: string;
-
}
-.. http:post:: /withdrawals/$WITHDRAWAL_ID/confirm
+.. http:post:: /withdrawals/$WITHDRAWAL_ID/check
Endpoint for providers to notify the terminal backend about a payment having
happened. This will cause the bank to validate the transaction and allow
@@ -288,6 +281,10 @@ Config
// backend to check that the credit was confirmed.
provider_transaction_id?: string;
+ // The fees which the customer had to pay to the
+ // provider
+ terminal_fees?: Amount;
+
// A user-specific identifier for quota checks.
user_uuid?: string;
@@ -295,9 +292,50 @@ Config
// may wish to use in this operation. May only be
// present if ``user_uuid`` is also given.
lock?: string;
-
}
+.. http:get:: /withdrawals/$WITHDRAWAL_ID
+
+ Query information about a withdrawal, identified by the ``WITHDRAWAL_ID``.
+
+ **Request:**
+
+ :query long_poll_ms:
+ *Optional.* If specified, the bank will wait up to ``long_poll_ms``
+ milliseconds for operationt state to be different from ``old_state`` before sending the HTTP
+ response. A client must never rely on this behavior, as the bank may
+ return a response immediately.
+ :query old_state:
+ *Optional.* Default to "pending".
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The withdrawal operation is known to the bank, and details are given
+ in the `BankWithdrawalOperationStatus` response body.
+ :http:statuscode:`404 Not found`:
+ The operation was not found.
+
+.. http:delete:: /withdrawals/$WITHDRAWAL_ID/abort
+
+ Aborts ``WITHDRAWAL_ID`` operation. Has no effect on an already aborted
+ operation. This endpoint can be used by the terminal if the terminal aborts
+ the transaction, ensuring that the operation is also aborted at the
+ bank.
+
+ **Request:**
+
+ The request body is empty.
+
+ **Response:**
+
+ :http:statuscode:`204 No content`:
+ The withdrawal operation has been aborted.
+ :http:statuscode:`404 Not found`:
+ The withdrawal operation was not found.
+ :http:statuscode:`409 Conflict`:
+ The withdrawal operation has been confirmed previously and
+ can't be aborted.
Endpoints for Integrated Sub-APIs
diff --git a/design-documents/023-taler-kyc.rst b/design-documents/023-taler-kyc.rst
index c20844b3..786b0ca7 100644
--- a/design-documents/023-taler-kyc.rst
+++ b/design-documents/023-taler-kyc.rst
@@ -200,12 +200,12 @@ user for *voluntary* KYC processes related to attestation (#7365).
Proposed Solution
=================
-The main state of an account is represented by a set of `KycRules` (the
+The main state of an account is represented by a set of `KYC rules <KycRule>` (the
`LegitimizationRuleSet`) which specify the current *rules* to apply to
transactions involving the account. Rules can *exposed* to the account owner,
or can be secret. Each *rule* specifies certain *conditions* which, if met,
-*trigger* a single specific *measure*. After a *rule* was *triggered* and
-before the *outcome* of the respective *measure* has been produced (say
+*trigger* a set of *measures*. After a *rule* was *triggered* and
+before the *outcome* of a respective *measure* has been produced (say
because the user did not yet enter their data or the AML officer is still
reviewing the case), the existing rules remain in force. Rules have a display
priority, and if a second rule with a higher display priority is also
@@ -431,48 +431,9 @@ expose merchant public key to SPA for wire transfer if needed for KYC.
^^^^^^^^^^^^
When KYC operations are required, various endpoints may respond with a
-``451 Unavailable for Legal Reasons`` status code and a `KycNeededRedirect`
+``451 Unavailable for Legal Reasons`` status code and a `LegitimziationNeededResponse`
body.
- .. ts:def:: KycNeededRedirect
-
- interface KycNeededRedirect {
-
- // Numeric `error code <error-codes>` unique to the condition.
- // Should always be ``TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED``.
- code: number;
-
- // Human-readable description of the error, i.e. "missing parameter",
- // "commitment violation", ... Should give a human-readable hint
- // about the error's nature. Optional, may change without notice!
- hint?: string;
-
- // Hash of the payto:// account URI for which KYC
- // is required.
- h_payto: PaytoHash;
-
- // Public key associated with the account. The client must sign
- // the initial request for the KYC status using the corresponding
- // private key. Will be either a reserve public key or a merchant
- // (instance) public key.
- //
- // Absent if no public key is currently associated
- // with the account and the client MUST thus first
- // credit the exchange via an inbound wire transfer
- // to associate a public key with the debited account.
- account_pub?: EddsaPublicKey;
-
- // Identifies a set of measures that were triggered and that are
- // now preventing this operation from proceeding. Gives the
- // account holder a starting point for understanding why the
- // transaction was blocked and how to lift it. The account holder
- // should use the number to check for the account's AML/KYC status
- // using the ``/kyc-check/$REQUIREMENT_ROW`` endpoint.
- requirement_row: Integer;
-
- }
-
-
New endpoints
^^^^^^^^^^^^^
@@ -489,7 +450,7 @@ New endpoints
The requirement row of the ``/kyc-check/`` endpoint encodes the
legitimization measure's serial number. It is returned in
- `KycNeededRedirect` responses via the ``requirement_row`` field.
+ `LegitimizationNeededResponse` responses via the ``requirement_row`` field.
Given a valid pair of requirement row and account owner signature, the
``/kyc-check/`` endpoint returns either just the KYC status or redirects the
@@ -543,79 +504,6 @@ New endpoints
:http:statuscode:`404 Not found`:
The requirement row is unknown.
- **Details:**
-
- .. ts:def:: AccountKycStatus
-
- interface AccountKycStatus {
-
- // Current AML state for the target account. True if
- // operations are not happening due to staff processing
- // paperwork *or* due to legal requirements (so the
- // client cannot do anything but wait).
- //
- // Note that not every AML staff action may be legally
- // exposed to the client, so this is merely a hint that
- // a client should be told that AML staff is currently
- // reviewing the account. AML staff *may* review
- // accounts without this flag being set!
- aml_review: boolean;
-
- // Access token needed to construct the ``/kyc-spa/``
- // URL that the user should open in a browser to
- // proceed with the KYC process (optional if the status
- // type is ``200 Ok``, mandatory if the HTTP status
- // is ``202 Accepted``).
- access_token: AccountAccessToken;
-
- // Array with limitations that currently apply to this
- // account and that may be increased or lifted if the
- // KYC check is passed.
- // Note that additional limits *may* exist and not be
- // communicated to the client. If such limits are
- // reached, this *may* be indicated by the account
- // going into ``aml_review`` state. However, it is
- // also possible that the exchange may legally have
- // to deny operations without being allowed to provide
- // any justification.
- // The limits should be used by the client to
- // possibly structure their operations (e.g. withdraw
- // what is possible below the limit, ask the user to
- // pass KYC checks or withdraw the rest after the time
- // limit is passed, warn the user to not withdraw too
- // much or even prevent the user from generating a
- // request that would cause it to exceed hard limits).
- limits?: AccountLimit[];
-
- }
-
- .. ts:def:: AccountLimit
-
- interface AccountLimit {
-
- // Operation that is limited.
- // Must be one of "WITHDRAW", "DEPOSIT", "P2P-RECEIVE"
- // or "WALLET-BALANCE".
- operation_type: string;
-
- // Timeframe during which the limit applies.
- timeframe: RelativeTime;
-
- // Maximum amount allowed during the given timeframe.
- // Zero if the operation is simply forbidden.
- threshold: Amount;
-
- // True if this is a soft limit that could be raised
- // by passing KYC checks. Clients *may* deliberately
- // try to cross limits and trigger measures resulting
- // in 451 responses to begin KYC processes.
- // Clients that are aware of hard limits *should*
- // inform users about the hard limit and prevent flows
- // in the UI that would cause violations of hard limits.
- soft_limit: boolean;
- }
-
-
.. http:get:: /kyc-spa/$ACCESS_TOKEN
.. http:get:: /kyc-spa/$FILENAME
@@ -656,72 +544,13 @@ New endpoints
**Response:**
+ *Etag*: Will be set to the serial ID of the measure. Used for long-polling (only for 200 OK responses).
+
:http:statuscode:`200 OK`:
The body is a `KycProcessClientInformation`.
-
- *Etag*: Will be set to the serial ID of the measure. Used for long-polling.
-
- .. ts:def:: KycProcessClientInformation
-
- interface KycProcessClientInformation {
-
- // List of requirements.
- requirements?: { name : KycRequirementInformation};
-
- // True if the client is expected to eventually satisfy all requirements.
- // Default (if missing) is false.
- is_and_combinator?: boolean
-
- // List of available voluntary checks the client could pay for.
- // Since **vATTEST**.
- voluntary_checks?: { name : KycCheckInformation};
- }
-
- .. ts:def:: KycRequirementInformation
-
- interface KycRequirementInformation {
-
- // Which form should be used? Common values include "INFO"
- // (to just show the descriptions but allow no action),
- // "LINK" (to enable the user to obtain a link via
- // ``/kyc-start/``) or any build-in form name supported
- // by the SPA.
- form: string;
-
- // English description of the requirement.
- description: string;
-
- // Map from IETF BCP 47 language tags to localized
- // description texts.
- description_i18n ?: { [lang_tag: string]: string };
-
- // ID of the requirement, useful to construct the
- // ``/kyc-upload/$ID`` or ``/kyc-start/$ID`` endpoint URLs.
- // Present if and only if "form" is not "INFO". The
- // ``$ID`` value may itself contain ``/`` or ``?`` and
- // basically encode any URL path (and optional arguments).
- id?: string;
-
- }
-
- .. ts:def:: KycCheckInformation
-
- // Since **vATTEST**.
- interface KycCheckInformation {
-
- // English description of the check.
- description: string;
-
- // Map from IETF BCP 47 language tags to localized
- // description texts.
- description_i18n ?: { [lang_tag: string]: string };
-
- }
-
:http:statuscode:`204 No Content`:
There are no open KYC requirements or possible voluntary checks
the client might perform.
-
:http:statuscode:`304 Not Modified`:
The KYC requirements did not change.
@@ -749,7 +578,7 @@ New endpoints
The ``$ID`` is unknown to the exchange.
:http:statuscode:`409 Conflict`:
The upload conflicts with a previous upload.
- :http:statuscode:`413 Content Too Large`:
+ :http:statuscode:`413 Request Entity Too Large`:
The body is too large.
.. http:post:: /kyc-start/$ID
@@ -771,16 +600,6 @@ New endpoints
The KYC process was successfully initiated. The URL is in a
`KycProcessStartInformation` object.
- **Details:**
-
- .. ts:def:: KycProcessStartInformation
-
- interface KycProcessStartInformation {
-
- // URL to open.
- redirect_url: string;
- }
-
:http:statuscode:`404 Not Found`:
The ``$ID`` is unknown to the exchange.
@@ -913,29 +732,7 @@ New endpoints
This response comes with a standard `ErrorDetail` response.
:http:statuscode:`451 Unavailable for Legal Reasons`:
The wallet must undergo a KYC check. A KYC ID was created.
- The response will be a `KycNeededRedirect` object.
-
- **Details:**
-
- .. ts:def:: WalletKycRequest
-
- interface WalletKycRequest {
-
- // Balance threshold (not necessarily exact balance)
- // to be crossed by the wallet that (may) trigger
- // additional KYC requirements.
- balance: Amount;
-
- // EdDSA signature of the wallet affirming the
- // request, must be of purpose
- // ``TALER_SIGNATURE_WALLET_ACCOUNT_SETUP``
- reserve_sig: EddsaSignature;
-
- // long-term wallet reserve-account
- // public key used to create the signature.
- reserve_pub: EddsaPublicKey;
- }
-
+ The response will be a `LegitimizationNeededResponse` object.
.. http:get:: /aml/$OFFICER_PUB/measures
@@ -959,86 +756,6 @@ New endpoints
Information about possible measures is returned in a
`AvailableMeasureSummary` object.
- **Details:**
-
- .. ts:def:: AvailableMeasureSummary
-
- interface AvailableMeasureSummary {
-
- // Available original measures that can be
- // triggered directly by default rules.
- roots: { "$measure_name" : MeasureInformation; };
-
- // Available AML programs.
- programs: { "$prog_name" : AmlProgramRequirement; };
-
- // Available KYC checks.
- checks: { "$check_name" : KycCheckInformation; };
-
- }
-
- .. ts:def:: MeasureInformation
-
- interface MeasureInformation {
-
- // Name of a KYC check.
- check_name: string;
-
- // Name of an AML program.
- prog_name: string;
-
- // Context for the check. Optional.
- context?: Object;
-
- }
-
- .. ts:def:: AmlProgramRequirement
-
- interface AmlProgramRequirement {
-
- // Description of what the AML program does.
- description: string;
-
- // List of required field names in the context to run this
- // AML program. SPA must check that the AML staff is providing
- // adequate CONTEXT when defining a measure using this program.
- context: string[];
-
- // List of required attribute names in the
- // input of this AML program. These attributes
- // are the minimum that the check must produce
- // (it may produce more).
- inputs: string[];
-
- }
-
- .. ts:def:: KycCheckInformation
-
- interface KycCheckInformation {
-
- // Description of the KYC check. Should be shown
- // to the AML staff but will also be shown to the
- // client when they initiate the check in the KYC SPA.
- description: string;
- description_i18n: {};
-
- // Names of the fields that the CONTEXT must provide
- // as inputs to this check.
- // SPA must check that the AML staff is providing
- // adequate CONTEXT when defining a measure using
- // this check.
- requires: string[];
-
- // Names of the attributes the check will output.
- // SPA must check that the outputs match the
- // required inputs when combining a KYC check
- // with an AML program into a measure.
- outputs: string[];
-
- // Name of a root measure taken when this check fails.
- fallback: string;
- }
-
.. http:get:: /aml/$OFFICER_PUB/kyc-statistics/$NAME
Returns the number of KYC events matching the given event type ``$NAME`` in
@@ -1064,13 +781,8 @@ New endpoints
**Response:**
- .. ts:def:: EventCounter
-
- interface EventCounter {
- // Number of events of the specified type in
- // the given range.
- counter: Integer;
- }
+ :http:statuscode:`200 OK`:
+ The responds will be an `EventCounter` message.
.. http:get:: /aml/$OFFICER_PUB/decisions
@@ -1116,31 +828,6 @@ New endpoints
:http:statuscode:`409 Conflict`:
The designated AML account is not enabled.
- **Details:**
-
- .. ts:def:: AmlDecisions
-
- interface AmlDecisions {
-
- // Array of AML decisions matching the query.
- records: AmlDecisions[];
- }
-
- .. ts:def:: AmlRecord
-
- interface AmlRecord {
-
- // Which payto-address is this record about.
- // Identifies a GNU Taler wallet or an affected bank account.
- h_payto: PaytoHash;
-
- // Row ID of the record. Used to filter by offset.
- rowid: Integer;
-
- // FIXME: more fields here!
- }
-
-
.. http:get:: /aml/$OFFICER_PUB/attributes/$H_PAYTO
Obtain attributes obtained as part of AML/KYC processes for a
@@ -1176,40 +863,7 @@ New endpoints
:http:statuscode:`409 Conflict`:
The designated AML account is not enabled.
- .. ts:def:: KycAttributes
-
- interface KycAttributes {
-
- // Matching KYC attribute history of the account.
- details: KycDetail[];
-
- }
-
- .. ts:def:: KycDetail
-
- // FIXME: bad name?
- interface KycDetail {
-
- // Row ID of the record. Used to filter by offset.
- rowid: Integer;
-
- // Name of the configuration section that specifies the provider
- // which was used to collect the attributes. NULL if they were
- // just uploaded via a form by the account owner.
- provider_section?: string;
-
- // The collected KYC data. NULL if the attribute data could not
- // be decrypted (internal error of the exchange, likely the
- // attribute key was changed).
- attributes?: Object;
-
- // Time when the KYC data was collected
- collection_time: Timestamp;
-
- }
-
-
- .. http:post:: /aml/$OFFICER_PUB/decision
+.. http:post:: /aml/$OFFICER_PUB/decision
Make an AML decision. Triggers the respective action and
records the justification.
@@ -1231,35 +885,6 @@ New endpoints
The designated AML account is not enabled or a more recent
decision was already submitted.
- **Details:**
-
- .. ts:def:: AmlDecision
-
- interface AmlDecision {
-
- // Human-readable justification for the decision.
- justification: string;
-
- // Which payto-address is the decision about?
- // Identifies a GNU Taler wallet or an affected bank account.
- h_payto: PaytoHash;
-
- // What are the new rules?
- new_rules: LegitimizationRuleSet;
-
- // True if the account should remain under investigation by AML staff.
- bool keep_investigating;
-
- // When was the decision made?
- decision_time: Timestamp;
-
- // Signature by the AML officer over a `TALER_AmlDecisionPS`.
- // Must have purpose ``TALER_SIGNATURE_MASTER_AML_KEY``.
- officer_sig: EddsaSignature;
-
- }
-
-
Modifications to existing endpoints
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1311,17 +936,6 @@ description of the high-level process for different providers.
# Which plugin is responsible for this provider?
LOGIC = PLUGIN_NAME
- # Optional cost, useful if clients want to voluntarily
- # trigger authentication procedures for attestation.
- # Since **vATTEST**.
- COST = EUR:5
-
- # Plus additional logic-specific options, e.g.:
- AUTHORIZATION_TOKEN = superdupersecret
-
- # Other logic-specific internal options (example):
- FORM_ID = business_legi_form
-
# Name of a program to run on the output of the plugin
# to convert the result into the desired set of attributes.
# The converter must create a log for the system administrator
@@ -1334,6 +948,17 @@ description of the high-level process for different providers.
# (when run regularly).
CONVERTER = taler-exchange-helper-$NAME
+ # Optional cost, useful if clients want to voluntarily
+ # trigger authentication procedures for attestation.
+ # Since **vATTEST**.
+ COST = EUR:5
+
+ # Plus additional logic-specific options, e.g.:
+ AUTHORIZATION_TOKEN = superdupersecret
+
+ # Other logic-specific internal options (example):
+ FORM_ID = business_legi_form
+
Configuration of possible KYC/AML checks
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1364,6 +989,7 @@ providers, one per configuration section:
VOLUNTARY = YES/NO
# Provider id, present only if type is LINK.
+ # Refers to a ``kyc-provider-$PROVIDER_ID`` section.
PROVIDER_ID = id
# Name of the SPA form, if type is FORM
@@ -1381,7 +1007,7 @@ providers, one per configuration section:
DESCRIPTION_I18N = "{"en":"Upload scan of your passport"}"
# ';'-separated list of fields that the CONTEXT must
- # provided as inputs to this check. For example,
+ # provide as inputs to this check. For example,
# for a FORM of type CHOICE, this might state
# ``choices: string[];``. The type after the ":"
# is for now purely for documentation and is
@@ -1391,8 +1017,11 @@ providers, one per configuration section:
# Description of the outputs provided by the check.
# Basically, the check's output is expected to
- # provide the following fields as inputs into
+ # provide the following fields as attribute inputs into
# a subsequent AML program.
+ # Only given for type FORM; INFO never has any outputs,
+ # and for type LINK we can obtain the same information
+ # from the CONVERTER via ``--list-outputs``.
OUTPUTS = business_name street city country registration
# **original** measure to take if the check fails
@@ -1422,7 +1051,7 @@ configuration section:
[kyc-rule-$RULE_NAME]
- # Operation that triggers this legitimization.
+ # Operation that triggers this rule.
# Must be one of WITHDRAW, DEPOSIT, P2P-RECEIVE
# or WALLET-BALANCE.
OPERATION_TYPE = WITHDRAW
@@ -1436,8 +1065,8 @@ configuration section:
# (under this set of rules).
NEXT_MEASURES = SWISSNESS KYB
- # "yes" if all NEXT_MEASURES will eventually need
- # to be satisfied, "no" if the user has a choice between
+ # "YES" if all NEXT_MEASURES will eventually need
+ # to be satisfied, "NO" if the user has a choice between
# them. Not actually enforced by the exchange, but
# primarily used to inform the user whether this is
# an "and" or "or". YES for "and".
@@ -1450,7 +1079,7 @@ configuration section:
# Defaults to NO if not set.
EXPOSED = YES
- # Threshold amount above which the legitimization is
+ # Threshold amount above which the rule is
# triggered. The total must be exceeded in the given
# timeframe.
THRESHOLD = KUDOS:100
@@ -1460,7 +1089,7 @@ configuration section:
# Ignored for WALLET-BALANCE. Can be 'forever'.
TIMEFRAME = 30 days
- # Enabled (default is NO)
+ # Set to YES to enable the rule (default is NO)
ENABLED = NO
@@ -1487,113 +1116,6 @@ AML programs are helper programs that can:
This is the default behavior if no command-line switches
are provided.
-.. ts:def:: AmlProgramInput
-
- interface AmlProgramInput {
-
- // JSON object that was provided as
- // part of the *measure*. This JSON object is
- // provided under "context" in the main JSON object
- // input to the AML program. This "context" should
- // satify both the REQUIRES clause of the respective
- // check and the output of "--requires" from the
- // AML program's command-line option.
- context?: Object;
-
- // JSON object that captures the
- // output of a ``[kyc-provider-]`` or (HTML) FORM.
- // The keys in the JSON object will be the attribute
- // names and the values must be strings representing
- // the data. In the case of file uploads, the data
- // MUST be base64-encoded.
- attributes: Object;
-
- // JSON array with the results of historic
- // AML desisions about the account.
- aml_history: AmlDecisionDetail[];
-
- // JSON array with the results of historic
- // KYC data about the account.
- kyc_history: KycDetail[];
-
- }
-
-.. ts:def:: AmlOutcome
-
- interface AmlOutcome {
-
- // Should the client's account be investigated
- // by AML staff?
- // Defaults to false.
- to_investigate?: boolean;
-
- // Free-form properties about the account.
- // Can be used to store properties such as PEP,
- // risk category, type of business, hits on
- // sanctions lists, etc.
- properties?: AccountProperties;
-
- // Types of events to add to the KYC events table.
- // (for statistics).
- events?: string[];
-
- // KYC rules to apply. Note that this
- // overrides *all* of the default rules
- // until the ``expiration_time`` and specifies
- // the successor measure to apply after the
- // expiration time.
- new_rules: LegitimizationRuleSet;
-
- }
-
-.. ts:def:: KycRule
-
- interface KycRule {
-
- // Type of operation to which the rule applies.
- operation_type: string;
-
- // The measures will be taken if the given
- // threshold is crossed over the given timeframe.
- threshold: Amount;
-
- // Over which duration should the ``threshold`` be
- // computed. All amounts of the respective
- // ``operation_type`` will be added up for this
- // duration and the sum compared to the ``threshold``.
- timeframe: RelativeTime;
-
- // Array of names of measures to apply.
- // Names listed can be original measures or
- // custom measures from the `AmlOutcome`.
- // A special measure "verboten" is used if the
- // threshold may never be crossed.
- measures: string[];
-
- // True if the rule (specifically, operation_type,
- // threshold, timeframe) and the general nature of
- // the measures (verboten or approval required)
- // should be exposed to the client.
- // Defaults to "false" if not set.
- exposed?: boolean;
-
- // True if all the measures will eventually need to
- // be satisfied, false if any of the measures should
- // do. Primarily used by the SPA to indicate how
- // the measures apply when showing them to the user;
- // in the end, AML programs will decide after each
- // measure what to do next.
- // Default (if missing) is false.
- is_and_combinator?: boolean;
-
- // If multiple rules apply to the same account
- // at the same time, the number with the highest
- // rule determines which set of measures will
- // be activated and thus become visible for the
- // user.
- display_priority: integer;
- }
-
If the AML program fails (exits with a failure code or
does not provide well-formed JSON output) the AML/KYC
process continues with the FALLBACK measure. This should
@@ -1646,8 +1168,9 @@ Finally, the configuration specifies a set of
# just an empty JSON object if there is none.
CONTEXT = {"choices":["individual","business"]}
- # Program to run on the context and check data to
+ # Program name to run on the context and check data to
# determine the outcome and next measure.
+ # Refers to a ``[aml-program-$PROG_NAME]`` section name.
PROGRAM = taler-aml-program
If no ``CHECK_NAME`` is provided at all, the AML ``PROGRAM`` is to be run
@@ -1738,6 +1261,8 @@ on GET ``/deposits/`` with the respective legitimization requirement row.
)
PARTITION BY HASH (access_token);
+ COMMENT ON TABLE legitimization_measures
+ IS 'Rules that have been triggered for the account (FIXME: check this is consistent with usage)';
COMMENT ON COLUMN legitimization_measures.access_token
IS 'Used to uniquely identify the account and as a symmetric access control mechanism for the SPA';
COMMENT ON COLUMN legitimization_measures.start_time
@@ -1885,86 +1410,13 @@ on GET ``/deposits/`` with the respective legitimization requirement row.
The ``jmeasures`` JSON in the ``legitimization_measures``
-table has is of type `LegitimizationMeasures`:
-
-.. ts:def:: LegitimizationMeasures
-
- interface LegitimizationMeasures {
-
- // Array of legitimization measures that
- // are to be applied.
- measures: MeasureInformation[];
-
- // True if the client is expected to eventually satisfy all requirements.
- // Default (if missing) is false.
- is_and_combinator?: boolean;
- }
-
+table is of type `LegitimizationMeasures`.
The ``jnew_rules`` JSON in the ``legitimization_outcomes``
-table has is of type `LegitimizationRuleSet`:
-
-.. ts:def:: LegitimizationRuleSet
-
- interface LegitimizationRuleSet {
-
- // When does this set of rules expire and
- // we automatically transition to the successor
- // measure?
- expiration_time: Timestamp;
-
- // Name of the measure to apply when the expiration time is
- // reached. If not set, we refer to the default
- // set of rules (and the default account state).
- successor_measure?: string;
-
- // Legitimization rules that are to be applied
- // to this account.
- rules: KycRule[];
-
- // Custom measures that KYC rules and the
- // ``successor_measure`` may refer to.
- custom_measures: { "$measure_name" : MeasureInformation; };
- }
-
-
-The ``jproperties`` JSON in the ``legitimization_outcomes`` table has is of
-type `AccountProperties`. All fields in this object are optional. The actual
-properties collected depend fully on the discretion of the exchange operator;
-however, some common fields are standardized and thus described here.
-
-.. ts:def:: AccountProperties
-
- interface AccountProperties {
-
- // True if this is a politically exposed account.
- // Rules for classifying accounts as politically
- // exposed are country-dependent.
- pep?: boolean;
-
- // True if this is a sanctioned account.
- // Rules for classifying accounts as sanctioned
- // are country-dependent.
- sanctioned?: boolean;
-
- // True if this is a high-risk account.
- // Rules for classifying accounts as at-risk
- // are exchange operator-dependent.
- high_risk?: boolean;
-
- // Business domain of the account owner.
- // The list of possible business domains is
- // operator- or country-dependent.
- business_domain?: string;
-
- // Is the client's account currently frozen?
- is_frozen?: boolean;
-
- // Was the client's account reported to the authorities?
- was_reported?: boolean;
-
- }
+table is of type `LegitimizationRuleSet`.
+The ``jproperties`` JSON in the ``legitimization_outcomes`` table is of
+type `AccountProperties`.
KYC forms
diff --git a/design-documents/046-mumimo-contracts.rst b/design-documents/046-mumimo-contracts.rst
index 8cb35316..7d2197d4 100644
--- a/design-documents/046-mumimo-contracts.rst
+++ b/design-documents/046-mumimo-contracts.rst
@@ -326,7 +326,7 @@ The contract terms v1 will have the following structure:
// Start of the validity period of the token.
valid_after: Timestamp;
- // Number of tokens to be yelded.
+ // Number of tokens to be issued.
// Defaults to one if the field is not provided.
number?: Integer;
diff --git a/design-documents/053-wallet-ui.rst b/design-documents/053-wallet-ui.rst
index 57f9b1f2..792f58e2 100644
--- a/design-documents/053-wallet-ui.rst
+++ b/design-documents/053-wallet-ui.rst
@@ -132,11 +132,6 @@ Issues
the "add" and "send" buttons on this page.
* WebEx (image): Screenshot does not show any
pending transactions.
-* Android (text): Uses "Exchange:" which is
- not user-facing terminology. Should only show the URLs.
-* Android (minor): Screenshot shows only a "pending"
- badge, which seems redundant given "+10 KUDOS inbound"
- (too much information?)
* iOS (major): Way too much detail shown, way too
much explanation text, too many operations
(send money, request payment, spend test money!!!!);
@@ -150,7 +145,6 @@ Issues
'tab' entirely!
* iOS (text): bad icon for "pending outgoing", the
"minus" sign does not give me good associations here
-* Android (text): Title should be *Balances* (plural)
* Android (minor): No "add" and "Send $CURRENCY" buttons
on this page.
@@ -288,8 +282,6 @@ Issues
payments and debit and POS) and again same icon
for invoice and withdraw) is sub-optimal. Should
pick unique icons for each type of operation.
-* Android (text): Button labels should just be
- "Send" and "Receive" (without "funds").
* iOS (text): Iconography (+ / -) is also not
expressive and redundant with the colors.
* iOS (text): Sign of the operation (+ / -) should
@@ -587,9 +579,7 @@ Issues
the amount **3** times. Maybe only show the amount
on top with the wire transfer details, and then at
the bottom show the fee ONCE *if* there is one?
-* Android(text): uses "exchange", which is verboten
* iOS(text): receiver name is missing, MUST be before IBAN
-* Android(text): wire transfer subject is third, should be first
* WebEx(screenshot): the screenshot does not show how to select an alternative bank (see: Netzbon). Would be nice to show that.
* Android(screenshot): the screenshot does not show how to select an alternative bank (see: Netzbon). Would be nice to show that.
@@ -648,8 +638,6 @@ Issues
* WebEx(text): not point in showing details if there are no fees.
* iOS(text): not point in showing details if there are no fees.
-* Android(text): still talks about 'exchange'
-* Android(text): has the amount twice, useless without fees
* iOS(text): status: Done is unnecessary, if we show this screen, it will always be 'done' (ok, theoretically in the middle of withdrawing, but the wire transfer will be done; but then maybe show 'incoming' but hide the status once really "done").
* unclear: "Delete" vs. 'Delete from history" --- two
styles, two translations, gain?
@@ -711,8 +699,6 @@ Actions
Issues
^^^^^^
-* Android(text) has button label "OK", should probably be "Open" for uniformity.
-* Android(text) has "Enter Taler URI", while WebEx has clearer text "enter taler:// URI".
* iOS (screenshot): lacks dialog (or screenshot?) entirely, not sure if we need manual URL-entry on mobile though, so could be OK!
@@ -825,7 +811,6 @@ Actions
Issues
^^^^^^
-* Android(text): details say receipt, but WebEx uses the slightly more accurate "Invoice ID". Could also use "Order #"?
* iOS(major): delete button is missing, instead only has "Done"
@@ -947,7 +932,6 @@ Actions
Issues
^^^^^^
-* Android(text): Webex uses "1 Week" instead of "7 days", let's use "week".
* iOS(text): 3 min/ 1h are inconsistent; other wallets have 1 day, 7 days, 30 days. We should be consistent.
diff --git a/design-documents/054-dynamic-form.rst b/design-documents/054-dynamic-form.rst
index d93b3684..5567fc60 100644
--- a/design-documents/054-dynamic-form.rst
+++ b/design-documents/054-dynamic-form.rst
@@ -1,10 +1,13 @@
-DD 54: Dynamic Web Form
-#######################
+DD 54: Dynamic Form
+###################
Summary
=======
-This document outlines the approach for implementing a dynamic web form feature.
+This document outlines the design of forms defined in the
+backend in a JSON file which will be rendered by a client
+for asking information to a person.
+
Motivation
==========
@@ -12,12 +15,16 @@ Motivation
Currently, creating a new form for a web app involves coding a new
page with HTML, CSS, and JS. Exchange AML requires multiple forms,
and different instances may have distinct forms based on jurisdiction.
+Being able to define forms in a JSON file that a client software
+(not just web SPA) could use to ask the information helps to change
+it without requiring a new upgrade of the client app.
Requirements
============
-A form consist of a layout and a set of fields.
+A form consist of a layout, a set of fields and metadata required to
+recognice which form configuration was used to produce the saved value.
Layout requirements
-------------------
@@ -41,159 +48,609 @@ Fields requirements
complex composite structure.
+Metadata requirements
+---------------------
+
+* **identification**: the form configuration instance should have an unique
+ non reusable id.
+
+* **label**: the form should have a name recognizable for the user
+
+* **version**: the same form, with the same id, could be updated. This will
+ increase the version number. A newer form should support older forms.
+
Proposed Solutions
==================
-Forms are initialized using a flexible structure defined by the
-TypeScript interface FormType<T>. This interface comprises properties
-such as value (current form data), initial (initial form data for resetting),
-readOnly (flag to disable input), onUpdate (callback on form data update),
-and computeFormState (function to derive the form state based on current data).
+The propose solution defines the structure of a form, the fields and additional
+type form-configuration which links a form with a set of fields.
+
+Form metadata
+-------------
+
+This is the root object of the configuration.
+.. code-block:: typescript
+
+ type FormMetadata = {
+ label: string;
+ id: string;
+ version: number;
+ config: FormConfiguration;
+ };
+
+
+Form configuration
+------------------
+
+Defies a basic structure and the set of fields the form is going to have.
+
+The ``FormConfiguration`` is an enumerated type which list can be extended in the
+future.
.. code-block:: typescript
- interface FormType<T extends object> {
- value: Partial<T>;
- initial?: Partial<T>;
- readOnly?: boolean;
- onUpdate?: (v: Partial<T>) => void;
- computeFormState?: (v: Partial<T>) => FormState<T>;
+ type FormConfiguration = DoubleColumnForm;
+
+ type DoubleColumnForm = {
+ type: "double-column";
+ design: DoubleColumnFormSection[];
}
+ type DoubleColumnFormSection = {
+ title: string;
+ description?: string;
+ fields: UIFormElementConfig[];
+ };
-``T``: is the type of the result object
-``value``: is a reference to the current value of the result
-``initial``: data for resetting
-``readOnly``: when true, fields won't allow input
-``onUpdate``: notification of the result update
-``computeFormState``: compute a new state of the form based on the current value
-Form state have the same shape of ``T`` but every field type is ``FieldUIOptions``.
+Form fields
+-----------
-Fields type can be:
- * strings
- * numbers
- * boolean
- * arrays
- * object
+A form can have two type of element: decorative/informative or input.
-The field type ``AmountJson`` and ``AbsoluteTime`` are opaque since field is used as a whole.
+An example of a decorative element is a grouping element which make all the fields
+inside the group look into the same section. This element will not allow the user
+to enter information and won't produce any value in the resulting JSON.
-The form can be instanciated using
+An example of an input field is a text field which allows the user to enter text.
+This element should have an ``id`` which will point into the location in which the
+value will be stored in the resulting JSON. Note that two field in the same form
+with the same ``id`` will result in undefined behavior.
+
+The ``UIFormElementConfig`` is an enumerated type with all type of fields supported
+
+.. code-block:: typescript
+
+ type UIFormElementConfig =
+ | UIFormElementGroup
+ | UIFormElementCaption
+ | UIFormFieldAbsoluteTime
+ | UIFormFieldAmount
+ | UIFormFieldArray
+ | UIFormFieldChoiseHorizontal
+ | UIFormFieldChoiseStacked
+ | UIFormFieldFile
+ | UIFormFieldInteger
+ | UIFormFieldSelectMultiple
+ | UIFormFieldSelectOne
+ | UIFormFieldText
+ | UIFormFieldTextArea
+ | UIFormFieldToggle;
+
+
+All form elements should extend from ``UIFieldElementDescription`` which defines a base
+configuration to show a field.
.. code-block:: typescript
- import { FormProvider } from "@gnu-taler/web-util/browser";
+ type UIFieldElementDescription = {
+ /* label if the field, visible for the user */
+ label: string;
+
+ /* long text to be shown on user demand */
+ tooltip?: string;
+
+ /* short text to be shown close to the field, usually below and dimmer*/
+ help?: string;
+
+ /* name of the field, useful for a11y */
+ name: string;
+ /* if the field should be initially hidden */
+ hidden?: boolean;
+
+ };
+
+That will be enough for a decorative form element (like group element or
+a text element) but if it defines an input field then it should extend
+from ``UIFormFieldBaseConfig`` which add more information to the previously
+defined ``UIFieldElementDescription``.
-Then the field component can access all the properties by the ``useField(name)`` hook,
-which will return
.. code-block:: typescript
- interface InputFieldHandler<Type> {
- value: Type;
- onChange: (s: Type) => void;
- state: FieldUIOptions;
- isDirty: boolean;
- }
+ type UIFormFieldBaseConfig = UIFieldElementDescription & {
+ /* example to be shown inside the field */
+ placeholder?: string;
+ /* show a mark as required */
+ required?: boolean;
-``value``: the current value of the field
-``onChange``: a function to call anytime the user want to change the value
-``state``: the state of the field (hidden, error, etc..)
-``isDirty``: if the user already tried to change the value
+ /* readonly and dim */
+ disabled?: boolean;
-A set of common form field exist in ``@gnu-taler/web-util``:
+ /* conversion id to convert the string into the value type
+ the id should be known to the ui impl
+ */
+ converterId?: string;
- * InputAbsoluteTime
- * InputAmount
- * InputArray
- * InputFile
- * InputText
- * InputToggle
+ /* property id of the form */
+ id: UIHandlerId;
+ };
-and should be used inside a ``Form`` context.
+ /**
+ * string which defined a json path
+ *
+ */
+ type UIHandlerId = string
-.. code-block:: none
- function MyFormComponent():VNode {
- return <FormProvider>
- <InputAmount name="amount" />
- <InputText name="subject" />
- <button type="submit"> Confirm </button>
- </FormProvider>
- }
+The ``id`` property defines the location in which this information is going
+to be saved in the JSON result. Formally formally, it should be a ``dot-selector``
+
+.. code-block:: ini
+
+ dot-selector = "." dot-member-name
+ dot-member-name = name-first *name-char
+ name-first = ALPHA / "_"
+ name-char = DIGIT / name-first
+
+ DIGIT = %x30-39 ; 0-9
+ ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+All the input fields will create a string value located where the id
+points, unless a ``convertedId`` is specified. The ``convertedId`` is a reference
+to a converter that the client software implements. For example, an input field
+with ``convertedId = "Taler.Amount"`` will transform the value the user
+entered into a *AmountString* with the currency in the configuration.
+
+
+Description of supported fields
+-------------------------------
+
+All of this fields defines an UI handler which help the user to input
+the value with as handy as possible. The type of the field doesn't define
+the type of the value in the resulting JSON, that's defined by the ``converterId``.
+
+Decorative elements
+```````````````````
+
+To show some additional text
+
+.. code-block:: typescript
+
+ type UIFormElementCaption = { type: "caption" } & UIFieldElementDescription;
+
+To group fields in the UI and maybe show a collapsable handler.
+
+.. code-block:: typescript
+
+ type UIFormElementGroup = {
+ type: "group";
+ fields: UIFormElementConfig[];
+ } & UIFieldElementDescription;
+
Example
---------
+'''''''
+
+.. code-block:: json
+
+ {
+ "label": "Example form",
+ "id": "example",
+ "version": 1,
+ "config": {
+ "type": "double-column",
+ "design": [
+ {
+ "title": "Decorative elements",
+ "fields": [
+ {
+ "type": "caption",
+ "name": "cap",
+ "label": "This is a caption"
+ },
+ {
+ "type": "group",
+ "name": "group",
+ "label": "The first name and last name are in a group",
+ "fields": [
+ {
+ "type": "text",
+ "name": "firstName",
+ "id": ".person.name",
+ "label": "First name"
+ },
+ {
+ "type": "text",
+ "name": "lastName",
+ "id": ".person.lastName",
+ "label": "Last name"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+.. image:: ../screenshots/dynamic-forms.decorative-elements.png
+ :width: 400
+
+Time input
+``````````
+
+This may be rendered as a calendar
+
+.. code-block:: typescript
+
+ type UIFormFieldAbsoluteTime = {
+ type: "absoluteTimeText";
+ max?: TalerProtocolTimestamp;
+ min?: TalerProtocolTimestamp;
+ pattern: string;
+ } & UIFormFieldBaseConfig;
+
+.. code-block:: json
+
+ {
+ "label": "Example form",
+ "id": "example",
+ "version": 1,
+ "config": {
+ "type": "double-column",
+ "design": [
+ {
+ "title": "Time inputs",
+ "fields": [
+ {
+ "type": "absoluteTime",
+ "name": "thedate",
+ "id": ".birthdate",
+ "converterId": "Taler.AbsoluteTime",
+ "help": "the day you born",
+ "pattern":"dd/MM/yyyy",
+ "label": "Birthdate"
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+.. image:: ../screenshots/dynamic-forms.time.png
+ :width: 400
+
+
+Amount input
+````````````
+
+Money input.
+
+.. code-block:: typescript
+
+ type UIFormFieldAmount = {
+ type: "amount";
+ max?: Integer;
+ min?: Integer;
+ currency: string;
+ } & UIFormFieldBaseConfig;
+
+.. code-block:: json
+
+ {
+ "label": "Example form",
+ "id": "example",
+ "version": 1,
+ "config": {
+ "type": "double-column",
+ "design": [
+ {
+ "title": "Amount inputs",
+ "fields": [
+ {
+ "type": "amount",
+ "name": "thedate",
+ "id": ".amount",
+ "converterId": "Taler.Amount",
+ "help": "how much do you have?",
+ "currency":"EUR",
+ "label": "Amount"
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+.. image:: ../screenshots/dynamic-forms.amount.png
+ :width: 400
-Consider a form shape represented by the TypeScript type:
+
+List input
+``````````
+
+This input allows to enter more than element in the same field, and the
+resulting JSON will have a json list. The UI should show the elements
+already present in the list, and for that it will use ``labelFieldId``.
.. code-block:: typescript
- type TheFormType = {
- name: string,
- age: number,
- savings: AmountJson,
- nextBirthday: AbsoluteTime,
- pets: string[],
- addres: {
- street: string,
- city: string,
+ type UIFormFieldArray = {
+ type: "array";
+ // id of the field shown when the array is collapsed
+ labelFieldId: UIHandlerId;
+ fields: UIFormElementConfig[];
+ } & UIFormFieldBaseConfig;
+
+.. code-block:: json
+
+ {
+ "label": "Example form",
+ "id": "example",
+ "version": 1,
+ "config": {
+ "type": "double-column",
+ "design": [
+ {
+ "title": "Amount inputs",
+ "fields": [
+ {
+ "type": "array",
+ "name": "people",
+ "id": ".people",
+ "help": "who is coming to the party?",
+ "labelFieldId": ".name",
+ "fields": [{
+ "type": "text",
+ "name": "firstName",
+ "id": ".name",
+ "label": "First name"
+ },
+ {
+ "type": "text",
+ "name": "lastName",
+ "id": ".lastName",
+ "label": "Last name"
+ }],
+ }
+ ]
+ }
+ ]
+ }
}
+
+
+.. image:: ../screenshots/dynamic-forms.list.png
+ :width: 400
+
+Choice input
+````````````
+
+To be used when the user need to choose on predefined values
+
+.. code-block:: typescript
+
+ interface SelectUiChoice {
+ label: string;
+ description?: string;
+ value: string;
}
-An example instance of this form could be:
+A set of buttons next to each other
.. code-block:: typescript
- const theFormValue: TheFormType = {
- name: "Sebastian",
- age: 15,
- pets: ["dog","cat"],
- address: {
- street: "long",
- city: "big",
+ type UIFormFieldChoiseHorizontal = {
+ type: "choiceHorizontal";
+ choices: Array<SelectUiChoice>;
+ } & UIFormFieldBaseConfig;
+
+
+A set of buttons next on top of each other
+
+.. code-block:: typescript
+
+ type UIFormFieldChoiseStacked = {
+ type: "choiceStacked";
+ choices: Array<SelectUiChoice>;
+ } & UIFormFieldBaseConfig;
+
+A drop down list to select one of the elements
+
+.. code-block:: typescript
+
+ type UIFormFieldSelectOne = {
+ type: "selectOne";
+ choices: Array<SelectUiChoice>;
+ } & UIFormFieldBaseConfig;
+
+A drop down list to select multiple of the element, which
+will produce a list of values in the resulting JSON.
+
+.. code-block:: typescript
+
+ type UIFormFieldSelectMultiple = {
+ type: "selectMultiple";
+ max?: Integer;
+ min?: Integer;
+ unique?: boolean;
+ choices: Array<SelectUiChoice>;
+ } & UIFormFieldBaseConfig;
+
+
+.. code-block:: json
+
+ {
+ "label": "Example form",
+ "id": "example",
+ "version": 1,
+ "config": {
+ "type": "double-column",
+ "design": [
+ {
+ "title": "Choice inputs",
+ "fields": [
+ {
+ "type": "choiceHorizontal",
+ "name": "food",
+ "label": "Food",
+ "id": ".food",
+ "choices": [
+ {
+ "value": "meat",
+ "label": "Meat"
+ },
+ {
+ "value": "sushi",
+ "label": "Sushi"
+ },
+ {
+ "value": "taco",
+ "label": "Taco"
+ },
+ {
+ "value": "salad",
+ "label": "Salad"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+.. image:: ../screenshots/dynamic-forms.choice.png
+ :width: 400
+
+File input
+``````````
+
+.. code-block:: typescript
+
+ type UIFormFieldFile = {
+ type: "file";
+ maxBytes?: Integer;
+ minBytes?: Integer;
+ // comma-separated list of one or more file types
+ // https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept#unique_file_type_specifiers
+ accept?: string;
+ } & UIFormFieldBaseConfig;
+
+
+.. code-block:: json
+
+ {
+ "label": "Example form",
+ "id": "example",
+ "version": 1,
+ "config": {
+ "type": "double-column",
+ "design": [
+ {
+ "title": "File inputs",
+ "fields": [
+ {
+ "type": "file",
+ "name": "photo",
+ "id": ".photo",
+ "label": "Photo",
+ "accept": "*.png"
+ }
+ ]
+ }
+ ]
}
}
+.. image:: ../screenshots/dynamic-forms.file.png
+ :width: 400
+
+Number input
+````````````
+
+.. code-block:: typescript
+
+ type UIFormFieldInteger = {
+ type: "integer";
+ max?: Integer;
+ min?: Integer;
+ } & UIFormFieldBaseConfig;
+
+
+.. image:: ../screenshots/dynamic-forms.number.png
+ :width: 400
+
+Text input
+``````````
+
+A simple line of text
-For such a form, a valid state can be computed using a function like
-``computeFormStateBasedOnFormValues``, returning an object indicating
-the state of each field, including properties such as ``hidden``,
-``disabled``, and ``required``.
-
-
-.. code-block:: javascript
-
- function computeFormStateBasedOnFormValues(formValues): {
- //returning fixed state as an example
- //the return state will be commonly be computed from the values of the form
- return {
- age: {
- hidden: true,
- },
- pets: {
- disabled: true,
- elements: [{
- disabled: false,
- }],
- },
- address: {
- street: {
- required: true,
- error: "the street name was not found",
- },
- city: {
- required: true,
- },
- },
+.. code-block:: typescript
+
+ type UIFormFieldText = { type: "text" } & UIFormFieldBaseConfig;
+
+A bigger multi-line of text
+
+.. code-block:: typescript
+
+ type UIFormFieldTextArea = { type: "textArea" } & UIFormFieldBaseConfig;
+
+
+.. image:: ../screenshots/dynamic-forms.text.png
+ :width: 400
+
+Boolean input
+`````````````
+
+.. code-block:: typescript
+
+ type UIFormFieldToggle = { type: "toggle" } & UIFormFieldBaseConfig;
+
+
+.. code-block:: json
+
+ {
+ "label": "Example form",
+ "id": "example",
+ "version": 1,
+ "config": {
+ "type": "double-column",
+ "design": [
+ {
+ "title": "Boolean inputs",
+ "fields": [
+ {
+ "type": "toggle",
+ "name": "the_question",
+ "id": ".the_question",
+ "label": "Yes or no?"
+ }
+ ]
+ }
+ ]
}
}
+.. image:: ../screenshots/dynamic-forms.boolean.png
+ :width: 400
+
+Examples
+========
diff --git a/frags/installing-ubuntu.rst b/frags/installing-ubuntu.rst
index f31b4ec6..89ca4dc9 100644
--- a/frags/installing-ubuntu.rst
+++ b/frags/installing-ubuntu.rst
@@ -17,7 +17,11 @@ For Ubuntu Mantic use this instead:
deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/ubuntu/ mantic taler-mantic
-The last line is crucial, as it adds the GNU Taler packages.
+For Ubuntu Noble use this instead:
+
+.. code-block::
+
+ deb [signed-by=/etc/apt/keyrings/taler-systems.gpg] https://deb.taler.net/apt/ubuntu/ noble taler-noble
Next, you must import the Taler Systems SA public package signing key
into your keyring and update the package lists:
diff --git a/images/grafana-postgres-exporter.png b/images/grafana-postgres-exporter.png
deleted file mode 100644
index a51c28f0..00000000
--- a/images/grafana-postgres-exporter.png
+++ /dev/null
Binary files differ
diff --git a/images/kuma.png b/images/kuma.png
deleted file mode 100644
index d98772a1..00000000
--- a/images/kuma.png
+++ /dev/null
Binary files differ
diff --git a/images/regional-arch.png b/images/regional-arch.png
deleted file mode 100644
index a3691aea..00000000
--- a/images/regional-arch.png
+++ /dev/null
Binary files differ
diff --git a/images/taler-monitoring-infrastructure.png b/images/taler-monitoring-infrastructure.png
deleted file mode 100644
index 05f29704..00000000
--- a/images/taler-monitoring-infrastructure.png
+++ /dev/null
Binary files differ
diff --git a/images/uptime-kuma-edit.png b/images/uptime-kuma-edit.png
deleted file mode 100644
index 23b85dad..00000000
--- a/images/uptime-kuma-edit.png
+++ /dev/null
Binary files differ
diff --git a/images/uptime-kuma-from-grafana.png b/images/uptime-kuma-from-grafana.png
deleted file mode 100644
index c42b8660..00000000
--- a/images/uptime-kuma-from-grafana.png
+++ /dev/null
Binary files differ
diff --git a/index.rst b/index.rst
index bd3b30d6..417e3a1b 100644
--- a/index.rst
+++ b/index.rst
@@ -18,6 +18,7 @@
@author Sree Harsha Totakura
@author Marcello Stanisci
@author Christian Grothoff
+ @author Javier Sepulveda
GNU Taler Documentation
=======================
@@ -63,6 +64,7 @@ Documentation Overview
taler-auditor-manual
taler-developer-manual
libeufin/index
+ system-administration/index
design-documents/index
global-licensing
manindex
diff --git a/libeufin/index.rst b/libeufin/index.rst
index c77255b0..4fd7668c 100644
--- a/libeufin/index.rst
+++ b/libeufin/index.rst
@@ -31,4 +31,5 @@ LibEuFin is a project providing free software tooling for European FinTech.
bank-manual
regional-automated-manual
regional-custom-manual
+ regional-manual-use
setup-ebics-at-postfinance
diff --git a/libeufin/regional-automated-manual.rst b/libeufin/regional-automated-manual.rst
index f416d1b9..39dfd3f6 100644
--- a/libeufin/regional-automated-manual.rst
+++ b/libeufin/regional-automated-manual.rst
@@ -241,7 +241,6 @@ manual setup and in the the manpage of ``taler-exchange-offline``.
.. include:: ../frags/regional-system-on.rst
.. include:: ../frags/deploying-tos.rst
-.. include:: ../frags/regional-manual-use.rst
Installing Updates
diff --git a/libeufin/regional-custom-manual.rst b/libeufin/regional-custom-manual.rst
index 7da39c96..4a347791 100644
--- a/libeufin/regional-custom-manual.rst
+++ b/libeufin/regional-custom-manual.rst
@@ -141,7 +141,6 @@ account with "CHF".
.. include:: ../frags/regional-system-on.rst
.. include:: ../frags/deploying-tos.rst
-.. include:: ../frags/regional-manual-use.rst
Maintenance
diff --git a/frags/regional-manual-use.rst b/libeufin/regional-manual-use.rst
index 7566d622..ff9f38f8 100644
--- a/frags/regional-manual-use.rst
+++ b/libeufin/regional-manual-use.rst
@@ -1,3 +1,22 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2024 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 2.1, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Florian Dold
+ @author Marcello Stanisci
+ @author Christian Grothoff
+
.. _regional-use:
Using the Regional Currency
diff --git a/manpages/libeufin-nexus.1.rst b/manpages/libeufin-nexus.1.rst
index a0ed99ff..5eb42cab 100644
--- a/manpages/libeufin-nexus.1.rst
+++ b/manpages/libeufin-nexus.1.rst
@@ -93,7 +93,7 @@ Its options are as follows:
Configure logging to use LOGLEVEL.
Uploaded documents will be stored *before* being submitted to the bank. This directory would contain several directories, each named after the ``YYYY-MM-DD/submit`` format. The pain.001 file would then be named in the following schema: ``$microseconds_pain.001.xml``.
**--transient**
- This flag, enabled by default, causes the command to check the database and submit only once, and then return.
+ This flag causes the command to check the database and submit only once, and then return.
ebics-fetch
@@ -105,6 +105,8 @@ The files type can be given as an argument to select what will be fetched. If no
* ``acknowledgement``: EBICS acknowledgement, retrieves the status of EBICS orders.
* ``status``: Payment status, retrieves status of pending debits.
+* ``report``: Account intraday reports, retrieves the history of confirmed debits and credits.
+* ``statement``: Account statements, retrieves the history of confirmed debits and credits.
* ``notification``: Debit & credit notifications, retrieves the history of confirmed debits and credits.
**-h** \| **--help**
@@ -117,10 +119,26 @@ The files type can be given as an argument to select what will be fetched. If no
Log EBICS content at SAVEDIR.
Downloaded documents will be stored *before* being ingested in the database. This directory would contain several directories, each named after the ``YYYY-MM-DD/fetch`` format. The stored files would then be named after the following schema: ``$microseconds_$filename``. Exception to this naming scheme are the HAC responses, since they do not get any filename assigned by the ZIP archive (they are sent unzipped). Their naming scheme is: ``$microseconds_HAC_response.pain.002.xml``.
**--transient**
- This flag, enabled by default, causes the command to perform one download and return.
+ This flag causes the command to perform one download and return.
**--pinned-start**
Only supported in --transient mode, this option lets specify the earliest timestamp of the downloaded documents. The latest timestamp is always the current time.
+serve
+-----
+
+This command starts the HTTP server.
+
+Its options are as follows:
+
+**-h** \| **--help**
+ Print short help on options.
+**-c** \| **--config** *FILENAME*
+ Specifies the configuration file.
+**-L** \| **--log** *LOGLEVEL*
+ Configure logging to use LOGLEVEL.
+**--check**
+ This flag causes the command to check whether an API is in use (if it's useful to start the HTTP server) and to output 0 if at least one API is enabled, otherwise 1.
+
initiate-payment
----------------
diff --git a/manpages/libeufin-nexus.conf.5.rst b/manpages/libeufin-nexus.conf.5.rst
index 9100f8fe..8aabe883 100644
--- a/manpages/libeufin-nexus.conf.5.rst
+++ b/manpages/libeufin-nexus.conf.5.rst
@@ -116,8 +116,8 @@ HOST_BASE_URL
BANK_DIALECT
Name of the following combination: EBICS version and ISO20022 recommendations
- that Nexus would honor in the communication with the bank. Currently only the
- 'postfinance' value is supported.
+ that Nexus would honor in the communication with the bank. Currently only the
+ ``postfinance`` or ``gls`` value is supported.
HOST_ID
EBICS specific: name of the EBICS host
@@ -167,6 +167,60 @@ FREQUENCY
IGNORE_TRANSACTIONS_BEFORE
Ignore all transactions before a certain YYYY-MM-DD date, useful when you want to use an existing account with old transactions that should not be bounced.
+HTTP SERVER OPTIONS
+-------------------
+
+The following configuration value(s) belong to the “[nexus-httpd]” section.
+
+SERVE
+ This can either be ``tcp`` or ``unix``.
+
+PORT
+ Port on which the HTTP server listens, e.g. 9967.
+ Only used if ``SERVE`` is ``tcp``.
+
+BIND_TO
+ Which IP address should we bind to? E.g. ``127.0.0.1`` or ``::1``for loopback. Can also be given as a hostname.
+ Only used if ``SERVE`` is ``tcp``.
+
+UNIXPATH
+ Which unix domain path should we bind to?
+ Only used if ``SERVE`` is ``unix``.
+
+UNIXPATH_MODE
+ What should be the file access permissions for ``UNIXPATH``?
+ Only used if ``SERVE`` is ``unix``.
+
+HTTP WIRE GATEWAY API OPTIONS
+-----------------------------
+
+The following configuration value(s) belong to the “[nexus-httpd-wire-gateway-api]” section.
+
+ENABLED
+ Whether to serve the Wire Gateway API.
+
+AUTH_METHOD
+ How to authenticate this API. This can either be ``none`` or ``bearer-token``.
+
+AUTH_BEARER_TOKEN
+ The expected token.
+ Only used if ``AUTH_METHOD`` is ``bearer-token``.
+
+HTTP REVENUE API OPTIONS
+------------------------
+
+The following configuration value(s) belong to the “[nexus-httpd-revenue-api]” section.
+
+ENABLED
+ Whether to serve the Revenue API.
+
+AUTH_METHOD
+ How to authenticate this API. This can either be ``none`` or ``bearer-token``.
+
+AUTH_BEARER_TOKEN
+ The expected token.
+ Only used if ``AUTH_METHOD`` is ``bearer-token``.
+
DATABASE OPTIONS
----------------
diff --git a/manpages/taler.conf.5.rst b/manpages/taler.conf.5.rst
index 3074f68b..ee5d3cd1 100644
--- a/manpages/taler.conf.5.rst
+++ b/manpages/taler.conf.5.rst
@@ -254,19 +254,29 @@ PRIVACY_ETAG
EXCHANGE KYC PROVIDER OPTIONS
-----------------------------
-The following options must be in the section "[kyc-provider-XXX]" sections.
-
-COST
- Relative cost of the KYC provider, non-negative number.
+The following options must be in the section "[kyc-provider-$PROVIDER_NAME]" sections.
LOGIC
API type of the KYC provider.
-USER_TYPE
- Type of user this provider is for, either INDIVIDUAL or BUSINESS.
+CONVERTER
+ Name of a program to run on the output of the plugin
+ to convert the result into the desired set of attributes.
+ The converter must create a log for the system administrator
+ if the provided inputs do not match expectations.
+ Note that the converter will be expected to output the
+ set of attributes listed under the respective ``[kyc-check-*]``
+ sections. Calling the converter with ``--list-outputs``
+ should generate a (newline-separated) list of attributes
+ the converter promises to generate in its JSON output
+ (when run regularly).
+
+COST
+ Optional cost, useful if clients want to voluntarily
+ trigger authentication procedures for attestation.
-PROVIDED_CHECKS
- List of checks performed by this provider. Space-separated names of checks, must match check names in legitimization rules.
+Additional logic-specific options may be given in the
+section.
EXCHANGE KYC OAUTH2 OPTIONS
@@ -362,6 +372,169 @@ WEBHOOK_AUTH_TOKEN
Authentication token Persona must supply to our webhook. This is an optional setting.
+EXCHANGE KYC CHECK OPTIONS
+--------------------------
+
+The following options must be in "[kyc-check-$CHECK_NAME]" sections.
+
+TYPE
+ Which type of check is this? Also determines
+ the SPA form to show to the user for this check.
+
+ * INFO: wait for staff or contact staff out-of band
+ (only information shown, no SPA action)
+ * FORM: SPA should show an inline (HTML) form
+ * LINK: SPA may start external KYC process or upload
+
+VOLUNTARY
+ Optional. Set to YES to allow this check be
+ done voluntarily by a client (they may then
+ still have to pay for it). Used to offer the
+ SPA to display checks even if they are
+ not required. Default is NO.
+
+PROVIDER_ID
+ Provider id, present only if type is LINK.
+ Refers to a ``kyc-provider-$PROVIDER_ID`` section.
+
+FORM_NAME
+ Name of the SPA form, if type is FORM
+ "INFO" and "LINK" are reserved and must not be used.
+ The exchange server and the SPA must agree on a list
+ of supported forms and the resulting attributes.
+ The SPA should include a JSON resource file
+ "forms.json" mapping form names to arrays of
+ attribute names each form provides.
+ The list of possible FORM names is fixed in the SPA
+ for a particular exchange release.
+
+DESCRIPTION
+ Descriptions to use in the SPA to display the check.
+
+DESCRIPTION_I18N
+ JSON with internationalized descriptions to use
+ in the SPA to display the check.
+
+REQUIRES
+ ';'-separated list of fields that the CONTEXT must
+ provide as inputs to this check. For example,
+ for a FORM of type CHOICE, this might state
+ ``choices: string[];``. The type after the ":"
+ is for now purely for documentation and is
+ not checked. However, it may be shown to AML staff
+ when they configure measures.
+
+OUTPUTS = business_name street city country registration
+ Description of the outputs provided by the check.
+ Basically, the check's output is expected to
+ provide the following fields as attribute inputs into
+ a subsequent AML program.
+ Only given for type FORM; INFO never has any outputs,
+ and for type LINK we can obtain the same information
+ from the CONVERTER via ``--list-outputs``.
+
+FALLBACK
+ Name of an **original** measure to take if the check fails
+ (for any reason, e.g. provider or form fail to
+ satisfy constraints or provider signals user error)
+ Usually should point to a measure that requests
+ AML staff to investigate. The fallback measure
+ context always includes the reasons for the
+ failure.
+
+EXCHANGE KYC RULES
+------------------
+
+The following options must be in "[kyc-rule-$RULE_NAME]" sections.
+
+OPERATION_TYPE = WITHDRAW
+ Operation that triggers this rule.
+ Must be one of WITHDRAW, DEPOSIT, P2P-RECEIVE
+ or WALLET-BALANCE.
+
+NEXT_MEASURES
+ Space-separated list of next measures to be performed.
+ The SPA should display *all* of these measures to the user.
+ (They have a choice of either which ones, or in
+ which order they are to be performed.)
+ A special measure name "verboten" is used if the
+ specified threshold may never be crossed
+ (under this set of rules).
+
+IS_AND_COMBINATOR
+ "YES" if all NEXT_MEASURES will eventually need
+ to be satisfied, "NO" the user has a choice between
+ them. Not actually enforced by the exchange, but
+ primarily used to inform the user whether this is
+ an "and" or "or". YES for "and".
+
+EXPOSED
+ YES if the rule (specifically, operation type,
+ threshold, timeframe) and the general nature of
+ the next measure (verboten or approval required)
+ should be exposed to the client.
+ Defaults to NO if not set.
+
+THRESHOLD
+ Threshold amount above which the rule is
+ triggered. The total must be exceeded in the given
+ timeframe.
+
+TIMEFRAME
+ Timeframe over which the amount to be compared to
+ the THRESHOLD is calculated (for example, "30 days").
+ Ignored for WALLET-BALANCE. Can be 'forever'.
+
+ENABLED = NO
+ Set to YES to enable the rule (default is NO).
+
+
+EXCHANGE AML PROGRAMS
+---------------------
+
+The following options must be in "[aml-program-$PROG_NAME]" sections.
+
+COMMAND
+ Name of the program to run. Must match a binary
+ on the local machine where the exchange is running.
+
+DESCRIPTION
+ Human-readable description of what this
+ AML helper program will do. Used to show
+ to the AML staff.
+
+ENABLED
+ True if this AML program is enabled (and thus can be
+ used in measures and exposed to AML staff).
+ Optional, default is NO.
+
+FALLBACK
+ Name of an **original** measure to take if COMMAND fails
+ Usually points to a measure that asks AML staff
+ to contact the systems administrator. The fallback measure
+ context always includes the reasons for the
+ failure.
+
+EXCHANGE KYC MEASURES
+---------------------
+
+The following options must be in "[kyc-measure-$MEASURE_NAME]" sections. These sections define the **original** measures.
+
+CHECK_NAME
+ Name of a possible check for this measure. Optional.
+ If not given, PROGRAM should be run immediately
+ (on an empty set of attributes).
+
+CONTEXT = {"choices":["individual","business"]}
+ Context for the check. The context can be
+ just an empty JSON object if there is none.
+
+PROGRAM
+ Program to run on the context and check data to
+ determine the outcome and next measure.
+ Refers to a ``[aml-program-$PROG_NAME]`` section name.
+
+
EXCHANGE EXTENSIONS OPTIONS
---------------------------
diff --git a/python-guidelines.rst b/orphaned/python-guidelines.rst
index 8a644ced..8a644ced 100644
--- a/python-guidelines.rst
+++ b/orphaned/python-guidelines.rst
diff --git a/checklists/qa-0.9.4.rst b/orphaned/qa-0.9.4.rst
index 77e51081..77e51081 100644
--- a/checklists/qa-0.9.4.rst
+++ b/orphaned/qa-0.9.4.rst
diff --git a/screenshots/cta-balance-list-android-1.png b/screenshots/cta-balance-list-android-1.png
new file mode 100644
index 00000000..ea552f77
--- /dev/null
+++ b/screenshots/cta-balance-list-android-1.png
Binary files differ
diff --git a/screenshots/cta-balance-list-android-latest.png b/screenshots/cta-balance-list-android-latest.png
index 90d09afe..6811c9de 120000
--- a/screenshots/cta-balance-list-android-latest.png
+++ b/screenshots/cta-balance-list-android-latest.png
@@ -1 +1 @@
-cta-balance-list-android-0.png \ No newline at end of file
+cta-balance-list-android-1.png \ No newline at end of file
diff --git a/screenshots/cta-payment-paid-android-1.png b/screenshots/cta-payment-paid-android-1.png
new file mode 100644
index 00000000..af6c5633
--- /dev/null
+++ b/screenshots/cta-payment-paid-android-1.png
Binary files differ
diff --git a/screenshots/cta-payment-paid-android-latest.png b/screenshots/cta-payment-paid-android-latest.png
index 8aabd17e..558aa216 120000
--- a/screenshots/cta-payment-paid-android-latest.png
+++ b/screenshots/cta-payment-paid-android-latest.png
@@ -1 +1 @@
-cta-payment-paid-android-0.png \ No newline at end of file
+cta-payment-paid-android-1.png \ No newline at end of file
diff --git a/screenshots/cta-peer-pull-initiate-android-1.png b/screenshots/cta-peer-pull-initiate-android-1.png
new file mode 100644
index 00000000..4109253c
--- /dev/null
+++ b/screenshots/cta-peer-pull-initiate-android-1.png
Binary files differ
diff --git a/screenshots/cta-peer-pull-initiate-android-latest.png b/screenshots/cta-peer-pull-initiate-android-latest.png
index eeb4d8c9..37cf7434 120000
--- a/screenshots/cta-peer-pull-initiate-android-latest.png
+++ b/screenshots/cta-peer-pull-initiate-android-latest.png
@@ -1 +1 @@
-cta-peer-pull-initiate-android-0.png \ No newline at end of file
+cta-peer-pull-initiate-android-1.png \ No newline at end of file
diff --git a/screenshots/cta-transaction-list-android-1.png b/screenshots/cta-transaction-list-android-1.png
new file mode 100644
index 00000000..c3ac2e4f
--- /dev/null
+++ b/screenshots/cta-transaction-list-android-1.png
Binary files differ
diff --git a/screenshots/cta-transaction-list-android-latest.png b/screenshots/cta-transaction-list-android-latest.png
index 9bf9ffa8..f5c83c2c 120000
--- a/screenshots/cta-transaction-list-android-latest.png
+++ b/screenshots/cta-transaction-list-android-latest.png
@@ -1 +1 @@
-cta-transaction-list-android-0.png \ No newline at end of file
+cta-transaction-list-android-1.png \ No newline at end of file
diff --git a/screenshots/cta-url-entry-android-1.png b/screenshots/cta-url-entry-android-1.png
new file mode 100644
index 00000000..4032bf5d
--- /dev/null
+++ b/screenshots/cta-url-entry-android-1.png
Binary files differ
diff --git a/screenshots/cta-url-entry-android-latest.png b/screenshots/cta-url-entry-android-latest.png
index 2cd152f8..053842c6 120000
--- a/screenshots/cta-url-entry-android-latest.png
+++ b/screenshots/cta-url-entry-android-latest.png
@@ -1 +1 @@
-cta-url-entry-android-0.png \ No newline at end of file
+cta-url-entry-android-1.png \ No newline at end of file
diff --git a/screenshots/cta-wire-transfer-android-1.png b/screenshots/cta-wire-transfer-android-1.png
new file mode 100644
index 00000000..0dd0e4b0
--- /dev/null
+++ b/screenshots/cta-wire-transfer-android-1.png
Binary files differ
diff --git a/screenshots/cta-wire-transfer-android-latest.png b/screenshots/cta-wire-transfer-android-latest.png
index f50509ba..38074199 120000
--- a/screenshots/cta-wire-transfer-android-latest.png
+++ b/screenshots/cta-wire-transfer-android-latest.png
@@ -1 +1 @@
-cta-wire-transfer-android-0.png \ No newline at end of file
+cta-wire-transfer-android-1.png \ No newline at end of file
diff --git a/screenshots/cta-withdraw-done-android-1.png b/screenshots/cta-withdraw-done-android-1.png
new file mode 100644
index 00000000..11fc66c5
--- /dev/null
+++ b/screenshots/cta-withdraw-done-android-1.png
Binary files differ
diff --git a/screenshots/cta-withdraw-done-android-latest.png b/screenshots/cta-withdraw-done-android-latest.png
index 7751f9d0..78f631b2 120000
--- a/screenshots/cta-withdraw-done-android-latest.png
+++ b/screenshots/cta-withdraw-done-android-latest.png
@@ -1 +1 @@
-cta-withdraw-done-android-0.png \ No newline at end of file
+cta-withdraw-done-android-1.png \ No newline at end of file
diff --git a/screenshots/dynamic-forms.amount.png b/screenshots/dynamic-forms.amount.png
new file mode 100644
index 00000000..854d901c
--- /dev/null
+++ b/screenshots/dynamic-forms.amount.png
Binary files differ
diff --git a/screenshots/dynamic-forms.boolean.png b/screenshots/dynamic-forms.boolean.png
new file mode 100644
index 00000000..92b1e3bd
--- /dev/null
+++ b/screenshots/dynamic-forms.boolean.png
Binary files differ
diff --git a/screenshots/dynamic-forms.choice.png b/screenshots/dynamic-forms.choice.png
new file mode 100644
index 00000000..5922322f
--- /dev/null
+++ b/screenshots/dynamic-forms.choice.png
Binary files differ
diff --git a/screenshots/dynamic-forms.decorative-elements.png b/screenshots/dynamic-forms.decorative-elements.png
new file mode 100644
index 00000000..4981b2e9
--- /dev/null
+++ b/screenshots/dynamic-forms.decorative-elements.png
Binary files differ
diff --git a/screenshots/dynamic-forms.file.png b/screenshots/dynamic-forms.file.png
new file mode 100644
index 00000000..0895b353
--- /dev/null
+++ b/screenshots/dynamic-forms.file.png
Binary files differ
diff --git a/screenshots/dynamic-forms.list.png b/screenshots/dynamic-forms.list.png
new file mode 100644
index 00000000..0f007254
--- /dev/null
+++ b/screenshots/dynamic-forms.list.png
Binary files differ
diff --git a/screenshots/dynamic-forms.time.png b/screenshots/dynamic-forms.time.png
new file mode 100644
index 00000000..00c8c57c
--- /dev/null
+++ b/screenshots/dynamic-forms.time.png
Binary files differ
diff --git a/system-administration/images/lego-logo.svg b/system-administration/images/lego-logo.svg
new file mode 100644
index 00000000..2b578d34
--- /dev/null
+++ b/system-administration/images/lego-logo.svg
@@ -0,0 +1 @@
+<svg width="538.167" height="152.232" viewBox="0 0 142.39 40.278" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g fill="none" stroke="#00add8" stroke-width="2.646"><path d="M129.04 6.615c-6.952 0-6.952 4.973-6.952 6.024V27.61c0 .62 0 6.053 6.952 6.053s6.735-5.423 6.735-6.053V12.64c0-1.013.217-6.024-6.735-6.024z"/><path d="M113.61 12.639c0-1.013.217-6.025-6.735-6.025s-6.952 4.973-6.952 6.025V27.61c0 .62 0 6.053 6.952 6.053s6.735-5.423 6.735-6.053v-7.465h-4.53" stroke-linecap="square"/></g><g fill="none" stroke="#00add8" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.323"><path d="M88.866 31.356v-3.374c0-1.472-.874-2.83-2.724-2.83H81.05m5.509 8.511a2.307 2.307 0 1 0 4.614 0 2.307 2.307 0 0 0-4.614 0zM86.559 20.145h-5.551m5.551 0a2.307 2.307 0 1 0 4.614 0 2.307 2.307 0 0 0-4.614 0zM88.866 8.922v3.374c0 1.472-.874 2.83-2.724 2.83H81.05m5.509-8.511a2.307 2.307 0 1 0 4.614 0 2.307 2.307 0 0 0-4.614 0z"/></g><path d="M62.737 13.728V9.291c-.001-3.22 2.772-5.887 5.993-5.889 3.221-.002 5.997 2.662 6 5.883.002 3.22 0 4.443 0 4.443" fill="none" stroke="#4db969" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.133" style="paint-order:fill markers stroke"/><rect x="60.158" y="13.728" width="17.047" height="12.13" ry="1.725" fill="#4db969" stroke="#4db969" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.117" style="paint-order:normal"/><g fill="#fff" stroke-width=".146"><path class="cls-4" d="M66.397 21.903a.414.414 0 0 0 .358-.206l.358-.62.285-.494.015-.025.906-1.571a.414.414 0 0 1 .717 0l.61 1.055a.412.412 0 1 0 .716-.412l-1.326-2.297a.414.414 0 0 0-.717 0l-2.28 3.947a.414.414 0 0 0 .358.623z"/><path class="cls-4" d="M73.172 22.73h-8.207a.414.414 0 0 1-.358-.62l3.713-6.432a.414.414 0 0 1 .716 0l2.759 4.774a.414.414 0 0 1-.358.62h-3.129a.412.412 0 1 0 0 .826h4.563a.414.414 0 0 0 .358-.62l-3.865-6.695a.414.414 0 0 0-.358-.208h-.652a.414.414 0 0 0-.359.208l-4.492 7.781a.411.411 0 0 0 0 .414l.326.564a.41.41 0 0 0 .357.207h8.987a.41.41 0 0 0 .357-.207.412.412 0 0 0-.358-.612zM73.226 19.629l.868 1.503a.412.412 0 1 0 .715-.414l-.868-1.501a.414.414 0 0 0-.715.412zM70.555 15.003l.284.491a.412.412 0 1 0 .715-.412l-.283-.49a.414.414 0 0 0-.716.411zM71.793 17.147l.478.829a.414.414 0 0 0 .716-.414l-.478-.829a.414.414 0 0 0-.716.414zM72.217 24.384h-.981a.414.414 0 0 0 0 .827h.98a.412.412 0 0 0 .357-.62.413.413 0 0 0-.356-.207zM69.327 24.384a.414.414 0 1 0 .001.828.414.414 0 0 0-.001-.828zM65.564 17.146l1.237-2.143a.414.414 0 0 0-.717-.412l-1.236 2.141a.414.414 0 1 0 .716.414zM63.269 21.132l1.346-2.332a.412.412 0 1 0-.715-.414l-1.346 2.332a.412.412 0 1 0 .715.414zM67.418 24.384h-2.28a.414.414 0 0 0 .002.827h2.278a.415.415 0 0 0 .358-.62.415.415 0 0 0-.358-.207z"/></g><g fill="none" stroke="#f9a11d" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.323"><path d="M48.523 31.356v-3.374c0-1.472.874-2.83 2.724-2.83h5.092m-5.509 8.511a2.307 2.307 0 1 1-4.614 0 2.307 2.307 0 0 1 4.614 0zM50.83 20.145h5.551m-5.551 0a2.307 2.307 0 1 1-4.614 0 2.307 2.307 0 0 1 4.614 0zM48.523 8.922v3.374c0 1.472.874 2.83 2.724 2.83h5.092M50.83 6.614a2.307 2.307 0 1 1-4.614 0 2.307 2.307 0 0 1 4.614 0z"/></g><g fill="none" stroke="#f9a11d" stroke-linecap="square"><path d="M34.821 20.145H24.104m13.285 13.518H24.104V6.614h13.285" stroke-width="2.646"/><path d="M6.615 33.663h10.9M6.615 6.614v27.049m0-27.049v27.049" stroke-width="2.381"/></g></svg>
diff --git a/system-administration/index.rst b/system-administration/index.rst
new file mode 100644
index 00000000..e573f7c8
--- /dev/null
+++ b/system-administration/index.rst
@@ -0,0 +1,26 @@
+..
+ This file is part of GNU TALER.
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free Software
+ Foundation; either version 2.1, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+
+ @author Javier Sepulveda
+
+System Administration tutorials
+##################################
+
+.. toctree::
+ :maxdepth: 1
+ :glob:
+
+ lego-certificates
+ taler-monitoring-infrastructure
diff --git a/system-administration/lego-certificates.rst b/system-administration/lego-certificates.rst
new file mode 100644
index 00000000..ebc35329
--- /dev/null
+++ b/system-administration/lego-certificates.rst
@@ -0,0 +1,131 @@
+.. image:: images/lego-logo.svg
+ :width: 300
+ :height: 150
+ :alt: lego logo
+
+What is Lego
+###############
+
+Let's Encrypt client and ACME library written in Go.
+
+* You can request new certificates
+* You can request new subdomain alt names for your current main certicate
+* You can renew certificates
+* You can revoke certificates
+* You can request certificates by using dynamic DNS (API access, with multiple providers)
+
+
+Why lego is better for managing certificates
+===============================================
+
+* The process is not considered a live process, so in case something goes wrong your websites won't break.
+* You can hook some actions after the renewal process, such as reloading Dovecot.
+* The process of either obtaining or renewing new certicates, doesn't require you to stop NGINX.
+* Lego just helps you to obtain the certificates as text files, which you can copy afterwards to the right locations to be used by NGINX.
+
+
+Requirements
+=============
+- A fully automation of installing and deploying Lego can be found in migration-exercise-stable.git/taler.net/lego-certificates
+- If you want to do things manually instead, you can execute the "install-lego.sh" file.
+- To use our script simply execute the "main-certs.sh" file, which not only will install lego on your system, but
+ will try to obtain certificates for the ones listed on the "domains" text file.
+- Lego can work with so many domain providers (dynamic DNS), so please make sure you have indicated the right
+ API credentials on the "envars" variables file for your domain provider. In our specific case, we use Joker.
+- Make sure either you are not using UFW or any firewall program, or that if you are using one, make sure you have opened beforehand
+ the port 80.
+
+Installation and deployment with a script
+#############################################
+
+#. Git clone migration-exercise-stable.git
+#. Navigate to the folder taler.net/lego-certificates
+#. Add your desired FQDNs in the "domains" text file
+#. Execute the "main-certs.sh" file as ./main-certs.sh
+
+Manually installing Lego
+===========================
+
+.. note ::
+ Just as an informative process, as this is fully automated by executing either the "install-lego.sh" or the "main-certs.sh" files.
+
+.. code-block:: console
+
+ $ wget https://github.com/go-acme/lego/releases/download/v4.16.1/lego_v4.16.1_linux_amd64.tar.gz
+ $ tar -axf lego_v4.16.1_linux_amd64.tar.gz
+ $ # If moving directly to /usr/local/bin, just copy the lego binary file to /usr/local/bin
+ $ cp /tmp/lego /usr/local/bin/
+ $ # If copying the binary to /opt/lego, make symbolic links to /usr/local/bin
+ $ cp /tmp/lego /opt/lego/
+ $ ln -s /usr/local/bin /opt/lego/lego
+
+Full documentation on how to use Lego can be found in: https://go-acme.github.io/lego/
+
+Usage of lego once it has been installed
+###############################################
+
+* Each time you want to add an additional domain to your setup, just add the FQDN to the "domains" text file
+* There is nothing else to do in your side now, the server itself will trigger automatically (systemd timer) the "renew-certs.service"
+* We have implemented the use of lego with systemd timers, so there is not additional maintenance
+
+Automatic renewal of certificates
+##################################
+
+We use systemd timers do undertake this.
+
+.. note ::
+ To check the systemd timer is running properly and "waiting", you can execute "systemctl status renew-certs.timer"
+
+More information: https://go-acme.github.io/lego/usage/cli/renew-a-certificate/
+
+
+Email notifications
+====================
+
+* Let's encrypt notifications will arrive to your configured email address.
+* You can specify your email address by editing the "envars" text file (variable "LEGO_ACCOUNT_EMAIL").
+* On each successful renewal, you will receive an email notification from the script.
+
+Additional information for troubleshooting
+###############################################
+
+Once you have the certificate generated files (/root/.lego/xxx.crt, /root/.lego/xxx.key)
+they will be copied to /etc/ssl/certs and /etc/ssl/private, respectively.
+
+How to configure NGINX to use your certificates
+##################################################
+
+In the NGINX virtualhost configuration file just include "include conf.d/talerssl.conf;" line, and
+make sure you have a file named "talerssl.conf" in the path: /etc/nginx/conf.d with the next content:
+
+.. code-block:: console
+
+ $ # Taler SSL defaults
+ $ # We're using one certificate with taler.net as primary name
+ $ # and everything else as alt name.
+ $ # These 2 next lines are the important ones, which refer to the certificates file (.crt), and its private key (.key)
+ $ ssl_certificate /etc/ssl/certs/taler.net.crt;
+ $ ssl_certificate_key /etc/ssl/private/taler.net.key;
+ $ ssl_session_cache shared:SSL:10m;
+ $ ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
+ $ add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
+
+
+Presence of Lego in our servers
+######################################
+
+* TUE - University of Eindhoven
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/taler-monitoring-infrastructure.rst b/system-administration/taler-monitoring-infrastructure.rst
index 3b809fb3..e1b26c3b 100644
--- a/taler-monitoring-infrastructure.rst
+++ b/system-administration/taler-monitoring-infrastructure.rst
@@ -24,14 +24,15 @@ GNU Taler monitoring
In order to check the availability of our server infrastructure, we use the Grafana and Uptime KUMA monitoring programs.
-On the one hand Grafana let us to see *graphically* the server consumption resources, and even alert us of some specific situations.
+On the one hand Grafana enables us to see *graphically* the server consumption resources, and even alert us of some specific situations.
On the other hand with a more basic tool such as Uptime KUMA (which does mostly ping and https checks),
-we get the very first status information, as the very first countermeasure.
+we get the very first status information, as a very first countermeasure.
Grafana
=======
- Our grafana instance can be reached at https://grafana.taler.net
+- Our grafana instance is installed on the (TUE) server
User accounts:
--------------
@@ -162,19 +163,22 @@ Grafana Alerting
Uptime Kuma
===========
-- URL: http://139.162.254.179:3001/dashboard
+- URL: https://uptimekuma.anastasis.lu (main)
- Users: One single administration account with full privileges.
-- Installation: With Docker
+- Installation: Without docker. All within the user home folder /home/uptime-kuma
+- Monitors almost all our servers, websites and certificates expiration dates.
+
+- URL: https://uptimekuma.taler.net
+- Users: One single administration account with full privileges.
+- Installation: Without docker. All within the user home folder /home/uptime-kuma
+- Monitors the "main" uptimekuma installation, to make sure it is up and running, and doing the monitoring properly.
.. image:: images/kuma.png
.. note::
- 1) In order to guarantee the KUMA is doing its work, it needs to be install 100% externally from the servers you want to monitor. (Server Kuma 1)
- 2) Also, it is important to monitor the KUMA server itself, so you don't endup without a monitoring system. (Server Kuma 2)
-
-In our case, we do both. We have the two Uptime KUMA servers completely outside our server infrastructure, so one monitors the other, and
-the latter one, monitors our own Taler servers.
+ 1) The main uptimekuma installation is under the server anastasis.lu
+ 2) The second uptimekuma installation on top, is installed on gv.taler.net.
Kuma monitor types
-------------------
@@ -187,9 +191,10 @@ expiration dates.
So in brief in our KUMA main server, we use these 3 monitor types (ping,https,certificate expiration) for each website that we monitor.
-Exceptionally for additional notifications, and specifically due of the importance of the Taler Operations server,
-we use in addition SMS notifications (clicksend provider). This way in case of KUMA detecting the Taler Operations unavailability,
-a SMS message will be sent to at the very least two persons from the deployment and operations department.
+Exceptionally for high priority notifications for essential services, and specifically due of the importance of the Taler Operations production
+server, we use in addition SMS notifications (Clicksend provider). This way in the case the main uptimekuma detecting the Taler Operations server unavailability, or any other essential service such as GIt,
+a SMS message would be sent to the system administrator and eventually some other team member of the deployment and operations department, for urgent action.
+
How to edit notifications:
diff --git a/taler-developer-manual.rst b/taler-developer-manual.rst
index 3035e55d..c225e747 100644
--- a/taler-developer-manual.rst
+++ b/taler-developer-manual.rst
@@ -368,12 +368,6 @@ you can add the nightly package sources.
$ wget -O - https://taler.net/taler-systems-nightly.gpg.key | apt-key add -
-Language-Specific Guidelines
-============================
-
-* :doc:`Python Guidelines <python-guidelines>`
-
-
Taler Deployment on gv.taler.net
================================
@@ -648,7 +642,7 @@ outside of this versioning. All tables of a GNU Taler component should live in
QA Plans
========
-.. include:: checklists/qa-0.9.4.rst
+.. include:: checklists/qa-0.10.rst
Releases
diff --git a/taler-exchange-manual.rst b/taler-exchange-manual.rst
index 91865f24..069b256c 100644
--- a/taler-exchange-manual.rst
+++ b/taler-exchange-manual.rst
@@ -1023,6 +1023,20 @@ Taler KYC Terminology
*cost*. Interaction with a provider is performed by provider-specific
*logic*.
+Configuration of possible KYC/AML checks
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The configuration specifies a set of possible KYC checks offered by external
+providers. The names of the configuration sections must being with
+``kyc-check-`` followed by an arbitrary ``$CHECK_NAME``.
+
+The list of possible FORM names is fixed in the SPA
+for a particular exchange release.
+
+The outcome of *any* check should always be uploaded encrypted into the
+``kyc_attributes`` table. It MUST include an ``expiration_time``.
+
+
KYC Configuration Options
-------------------------
@@ -1724,6 +1738,155 @@ from ``https://git.taler.net/wallet-core.git/``, compile and copy the file
from the ``dist/prod``.
+AML Programs
+------------
+
+AML programs are helper programs that can:
+
+* Generate a list of *required* context field names
+ for the helper (introspection!) using the "--required-context"
+ command-line switch. The output should use the same
+ syntax as the REQUIRES clause of ``[kyc-check-]``
+ configuration sections, except that new lines
+ MUST be used to separate fields instead of ";".
+* Generate a list of *required* attribute names
+ for the helper (introspection!) using the "--required-attributes"
+ command-line switch. The output should use the same
+ list of names as the ATTRIBUTES in the
+ ``[kyc-provider-]`` configuration section
+ (but may also include FORM field names).
+* Process an input JSON object of type
+ `AmlProgramInput` into a JSON object of
+ type `AmlOutcome`.
+ This is the default behavior if no command-line switches
+ are provided.
+
+.. ts:def:: AmlProgramInput
+
+ interface AmlProgramInput {
+
+ // JSON object that was provided as
+ // part of the *measure*. This JSON object is
+ // provided under "context" in the main JSON object
+ // input to the AML program. This "context" should
+ // satify both the REQUIRES clause of the respective
+ // check and the output of "--requires" from the
+ // AML program's command-line option.
+ context?: Object;
+
+ // JSON object that captures the
+ // output of a ``[kyc-provider-]`` or (HTML) FORM.
+ // The keys in the JSON object will be the attribute
+ // names and the values must be strings representing
+ // the data. In the case of file uploads, the data
+ // MUST be base64-encoded.
+ attributes: Object;
+
+ // JSON array with the results of historic
+ // AML desisions about the account.
+ aml_history: AmlDecisionDetail[];
+
+ // JSON array with the results of historic
+ // KYC data about the account.
+ kyc_history: KycDetail[];
+
+ }
+
+.. ts:def:: AmlOutcome
+
+ interface AmlOutcome {
+
+ // Should the client's account be investigated
+ // by AML staff?
+ // Defaults to false.
+ to_investigate?: boolean;
+
+ // Free-form properties about the account.
+ // Can be used to store properties such as PEP,
+ // risk category, type of business, hits on
+ // sanctions lists, etc.
+ properties?: AccountProperties;
+
+ // Types of events to add to the KYC events table.
+ // (for statistics).
+ events?: string[];
+
+ // KYC rules to apply. Note that this
+ // overrides *all* of the default rules
+ // until the ``expiration_time`` and specifies
+ // the successor measure to apply after the
+ // expiration time.
+ new_rules: LegitimizationRuleSet;
+
+ }
+
+If the AML program fails (exits with a failure code or
+does not provide well-formed JSON output) the AML/KYC
+process continues with the FALLBACK measure. This should
+usually be one that asks AML staff to contact the
+systems administrator.
+
+AML programs are listed in the configuration file, one program per section:
+
+.. code-block:: ini
+
+ [aml-program-$PROG_NAME]
+
+ # Program to run.
+ COMMAND = taler-helper-aml-pep
+
+ # Human-readable description of what this
+ # AML helper program will do. Used to show
+ # to the AML staff.
+ DESCRIPTION = "check if the customer is a PEP"
+
+ # True if this AML program is enabled (and thus can be
+ # used in measures and exposed to AML staff).
+ # Optional, default is NO.
+ ENABLED = YES
+
+ # **original** measure to take if COMMAND fails
+ # Usually points to a measure that asks AML staff
+ # to contact the systems administrator. The fallback measure
+ # context always includes the reasons for the
+ # failure.
+ FALLBACK = MEASURE_NAME
+
+AML Measures
+------------
+
+The exchange configuration specifies a set of
+**original** *measures* one per configuration section:
+
+.. code-block:: ini
+
+ [kyc-measure-$MEASURE_NAME]
+
+ # Possible check for this measure. Optional.
+ # If not given, PROGRAM should be run immediately
+ # (on an empty set of attributes).
+ CHECK_NAME = IB_FORM
+
+ # Context for the check. The context can be
+ # just an empty JSON object if there is none.
+ CONTEXT = {"choices":["individual","business"]}
+
+ # Program to run on the context and check data to
+ # determine the outcome and next measure.
+ PROGRAM = taler-aml-program
+
+If no ``CHECK_NAME`` is provided at all, the AML ``PROGRAM`` is to be run
+immediately. This is useful if no client-interaction is required to arrive at
+a decision.
+
+.. note::
+
+ The list of *measures* is not complete: AML staff may freely define new
+ measures dynamically, usually by selecting checks, an AML program, and
+ providing context.
+
+
+
Setup Linting
=============
@@ -1902,6 +2065,22 @@ The database scheme used by the exchange looks as follows:
.. image:: images/exchange-db.png
+The ``jmeasures`` JSON in the ``legitimization_measures``
+table is of type `LegitimizationMeasures`:
+
+.. ts:def:: LegitimizationMeasures
+
+ interface LegitimizationMeasures {
+
+ // Array of legitimization measures that
+ // are to be applied.
+ measures: MeasureInformation[];
+
+ // True if the client is expected to eventually satisfy all requirements.
+ // Default (if missing) is false.
+ is_and_combinator?: boolean;
+ }
+
.. _Database-upgrades:
diff --git a/taler-merchant-manual.rst b/taler-merchant-manual.rst
index 353885cd..c647d3a2 100644
--- a/taler-merchant-manual.rst
+++ b/taler-merchant-manual.rst
@@ -635,11 +635,9 @@ section, the following options need to be configured:
Note that multiple exchanges can be added to the system by using different
-identifiers in place of ``KUDOS`` in the example above. Note that all of the
-exchanges actually used will use the same currency: If the currency does not
-match the main ``CURRENCY`` option from the ``taler`` section, the respective
-``merchant-exchange-`` section is automatically ignored. If you need support
-for multiple currencies, you need to deploy one backend per currency.
+identifiers in place of ``KUDOS`` in the example above. One exchange will only
+ever support a single currency; thus, if you need support for multiple
+currencies, you must add multiple exchanges.
The merchant already ships with a default configuration that contains the
``merchant-exchange-kudos`` section from above.
diff --git a/taler-merchant-pos-terminal.rst b/taler-merchant-pos-terminal.rst
index efc487cb..50e7ff97 100644
--- a/taler-merchant-pos-terminal.rst
+++ b/taler-merchant-pos-terminal.rst
@@ -106,19 +106,6 @@ The elements of the JSON file are defined as follows:
api_key: string;
}
- .. ts:def:: MerchantCategory
-
- interface MerchantCategory {
- // A unique numeric ID of the category
- id: number;
-
- // The name of the category. This will be shown to users and used in the order summary.
- name: string;
-
- // Map from IETF BCP 47 language tags to localized names
- name_i18n?: { [lang_tag: string]: string };
- }
-
.. ts:def:: MerchantProduct
diff --git a/wallet/wallet-core.md b/wallet/wallet-core.md
index 8c600081..56388f82 100644
--- a/wallet/wallet-core.md
+++ b/wallet/wallet-core.md
@@ -3,8 +3,10 @@ This file is auto-generated from [wallet-core](https://git.taler.net/wallet-core
## Overview
### Unknown Group
* [InitWalletOp](#initwalletop)
+* [ShutdownOp](#shutdownop)
* [SetWalletRunConfigOp](#setwalletrunconfigop)
* [GetVersionOp](#getversionop)
+* [HintNetworkAvailabilityOp](#hintnetworkavailabilityop)
### Basic Wallet Information
* [GetBalancesOp](#getbalancesop)
* [GetBalancesDetailOp](#getbalancesdetailop)
@@ -30,11 +32,14 @@ This file is auto-generated from [wallet-core](https://git.taler.net/wallet-core
### Withdrawals
* [GetWithdrawalDetailsForAmountOp](#getwithdrawaldetailsforamountop)
* [GetWithdrawalDetailsForUriOp](#getwithdrawaldetailsforuriop)
+* [PrepareBankIntegratedWithdrawalOp](#preparebankintegratedwithdrawalop)
+* [ConfirmWithdrawalOp](#confirmwithdrawalop)
* [AcceptBankIntegratedWithdrawalOp](#acceptbankintegratedwithdrawalop)
* [AcceptManualWithdrawalOp](#acceptmanualwithdrawalop)
### Merchant Payments
* [PreparePayForUriOp](#preparepayforuriop)
* [SharePaymentOp](#sharepaymentop)
+* [CheckPayForTemplateOp](#checkpayfortemplateop)
* [PreparePayForTemplateOp](#preparepayfortemplateop)
* [GetContractTermsDetailsOp](#getcontracttermsdetailsop)
* [ConfirmPayOp](#confirmpayop)
@@ -92,6 +97,7 @@ This file is auto-generated from [wallet-core](https://git.taler.net/wallet-core
* [ConfirmPeerPullDebitOp](#confirmpeerpulldebitop)
### Data Validation
* [ValidateIbanOp](#validateibanop)
+* [CanonicalizeBaseUrlOp](#canonicalizebaseurlop)
### Database Management
* [ExportDbOp](#exportdbop)
* [ImportDbOp](#importdbop)
@@ -111,9 +117,11 @@ This file is auto-generated from [wallet-core](https://git.taler.net/wallet-core
* [TestingSetTimetravelOp](#testingsettimetravelop)
* [TestingListTasksForTransactionOp](#testinglisttasksfortransactionop)
* [TestingWaitTransactionsFinalOp](#testingwaittransactionsfinalop)
+* [TestingWaitTasksDoneOp](#testingwaittasksdoneop)
* [TestingWaitRefreshesFinalOp](#testingwaitrefreshesfinalop)
* [TestingWaitTransactionStateOp](#testingwaittransactionstateop)
* [TestingPingOp](#testingpingop)
+* [TestingGetReserveHistoryOp](#testinggetreservehistoryop)
* [TestingGetDenomStatsOp](#testinggetdenomstatsop)
* [SetCoinSuspendedOp](#setcoinsuspendedop)
* [ForceRefreshOp](#forcerefreshop)
@@ -134,6 +142,17 @@ export type InitWalletOp = {
```
+### ShutdownOp
+```typescript
+export type ShutdownOp = {
+ op: WalletApiOperation.Shutdown;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// Shutdown = "shutdown"
+
+```
+
### SetWalletRunConfigOp
```typescript
/**
@@ -161,6 +180,23 @@ export type GetVersionOp = {
```
+### HintNetworkAvailabilityOp
+```typescript
+export type HintNetworkAvailabilityOp = {
+ op: WalletApiOperation.HintNetworkAvailability;
+ request: HintNetworkAvailabilityRequest;
+ response: EmptyObject;
+};
+// HintNetworkAvailability = "hintNetworkAvailability"
+
+```
+```typescript
+export interface HintNetworkAvailabilityRequest {
+ isNetworkAvailable: boolean;
+}
+
+```
+
### GetBalancesOp
```typescript
/**
@@ -645,6 +681,18 @@ export interface GetWithdrawalDetailsForAmountRequest {
exchangeBaseUrl: string;
amount: AmountString;
restrictAge?: number;
+ /**
+ * ID provided by the client to cancel the request.
+ *
+ * If the same request is made again with the same clientCancellationId,
+ * all previous requests are cancelled.
+ *
+ * The cancelled request will receive an error response with
+ * an error code that indicates the cancellation.
+ *
+ * The cancellation is best-effort, responses might still arrive.
+ */
+ clientCancellationId?: string;
}
```
@@ -711,7 +759,6 @@ export type GetWithdrawalDetailsForUriOp = {
export interface GetWithdrawalDetailsForUriRequest {
talerWithdrawUri: string;
restrictAge?: number;
- notifyChangeFromPendingTimeoutMs?: number;
}
```
@@ -735,10 +782,61 @@ export type WithdrawalOperationStatus =
```
+### PrepareBankIntegratedWithdrawalOp
+```typescript
+/**
+ * Prepare a bank-integrated withdrawal operation.
+ */
+export type PrepareBankIntegratedWithdrawalOp = {
+ op: WalletApiOperation.PrepareBankIntegratedWithdrawal;
+ request: PrepareBankIntegratedWithdrawalRequest;
+ response: PrepareBankIntegratedWithdrawalResponse;
+};
+// PrepareBankIntegratedWithdrawal = "prepareBankIntegratedWithdrawal"
+
+```
+```typescript
+export interface PrepareBankIntegratedWithdrawalRequest {
+ talerWithdrawUri: string;
+ exchangeBaseUrl: string;
+ forcedDenomSel?: ForcedDenomSel;
+ restrictAge?: number;
+}
+
+```
+```typescript
+export interface PrepareBankIntegratedWithdrawalResponse {
+ transactionId: string;
+}
+
+```
+
+### ConfirmWithdrawalOp
+```typescript
+/**
+ * Confirm a withdrawal transaction.
+ */
+export type ConfirmWithdrawalOp = {
+ op: WalletApiOperation.ConfirmWithdrawal;
+ request: ConfirmWithdrawalRequest;
+ response: EmptyObject;
+};
+// ConfirmWithdrawal = "confirmWithdrawal"
+
+```
+```typescript
+export interface ConfirmWithdrawalRequest {
+ transactionId: string;
+}
+
+```
+
### AcceptBankIntegratedWithdrawalOp
```typescript
/**
* Accept a bank-integrated withdrawal.
+ *
+ * @deprecated in favor of prepare/confirm withdrawal.
*/
export type AcceptBankIntegratedWithdrawalOp = {
op: WalletApiOperation.AcceptBankIntegratedWithdrawal;
@@ -784,6 +882,14 @@ export interface AcceptManualWithdrawalRequest {
exchangeBaseUrl: string;
amount: AmountString;
restrictAge?: number;
+ /**
+ * Instead of generating a fresh, random reserve key pair,
+ * use the provided reserve private key.
+ *
+ * Use with caution. Usage of this field may be restricted
+ * to developer mode.
+ */
+ forceReservePriv?: EddsaPrivateKeyString;
}
```
@@ -849,6 +955,53 @@ export interface SharePaymentResult {
```
+### CheckPayForTemplateOp
+```typescript
+export type CheckPayForTemplateOp = {
+ op: WalletApiOperation.CheckPayForTemplate;
+ request: CheckPayTemplateRequest;
+ response: TalerMerchantApi.WalletTemplateDetails;
+};
+// CheckPayForTemplate = "checkPayForTemplate"
+
+```
+```typescript
+export interface CheckPayTemplateRequest {
+ talerPayTemplateUri: string;
+}
+
+```
+```typescript
+export interface WalletTemplateDetails {
+ template_contract: TemplateContractDetails;
+ editable_defaults?: TemplateContractDetailsDefaults;
+ required_currency?: string;
+}
+
+```
+```typescript
+export interface TemplateContractDetails {
+ summary?: string;
+ currency?: string;
+ amount?: AmountString;
+ minimum_age: Integer;
+ pay_duration: RelativeTime;
+}
+
+```
+```typescript
+export interface TemplateContractDetailsDefaults {
+ summary?: string;
+ currency?: string;
+ /**
+ * Amount *or* a plain currency string.
+ */
+ amount?: string;
+ minimum_age?: Integer;
+}
+
+```
+
### PreparePayForTemplateOp
```typescript
/**
@@ -882,7 +1035,8 @@ export type GetContractTermsDetailsOp = {
```
```typescript
export interface GetContractTermsDetailsRequest {
- proposalId: string;
+ proposalId?: string;
+ transactionId?: string;
}
```
@@ -2374,6 +2528,29 @@ export interface ValidateIbanResponse {
```
+### CanonicalizeBaseUrlOp
+```typescript
+export type CanonicalizeBaseUrlOp = {
+ op: WalletApiOperation.CanonicalizeBaseUrl;
+ request: CanonicalizeBaseUrlRequest;
+ response: CanonicalizeBaseUrlResponse;
+};
+// CanonicalizeBaseUrl = "canonicalizeBaseUrl"
+
+```
+```typescript
+export interface CanonicalizeBaseUrlRequest {
+ url: string;
+}
+
+```
+```typescript
+export interface CanonicalizeBaseUrlResponse {
+ url: string;
+}
+
+```
+
### ExportDbOp
```typescript
/**
@@ -2596,11 +2773,28 @@ export type GetPendingTasksOp = {
export type GetActiveTasksOp = {
op: WalletApiOperation.GetActiveTasks;
request: EmptyObject;
- response: GetActiveTasks;
+ response: GetActiveTasksResponse;
};
// GetActiveTasks = "getActiveTasks"
```
+```typescript
+export interface GetActiveTasksResponse {
+ tasks: ActiveTask[];
+}
+
+```
+```typescript
+export interface ActiveTask {
+ taskId: string;
+ transaction: TransactionIdStr | undefined;
+ firstTry: AbsoluteTime | undefined;
+ nextTry: AbsoluteTime | undefined;
+ retryCounter: number | undefined;
+ lastError: TalerErrorDetail | undefined;
+}
+
+```
### DumpCoinsOp
```typescript
@@ -2819,6 +3013,20 @@ export type TestingWaitTransactionsFinalOp = {
```
+### TestingWaitTasksDoneOp
+```typescript
+/**
+ * Wait until all transactions are in a final state.
+ */
+export type TestingWaitTasksDoneOp = {
+ op: WalletApiOperation.TestingWaitTasksDone;
+ request: EmptyObject;
+ response: EmptyObject;
+};
+// TestingWaitTasksDone = "testingWaitTasksDone"
+
+```
+
### TestingWaitRefreshesFinalOp
```typescript
/**
@@ -2865,6 +3073,17 @@ export type TestingPingOp = {
```
+### TestingGetReserveHistoryOp
+```typescript
+export type TestingGetReserveHistoryOp = {
+ op: WalletApiOperation.TestingGetReserveHistory;
+ request: EmptyObject;
+ response: any;
+};
+// TestingGetReserveHistory = "testingGetReserveHistory"
+
+```
+
### TestingGetDenomStatsOp
```typescript
/**
@@ -2954,6 +3173,7 @@ export interface PartialWalletRunConfig {
builtin?: Partial<WalletRunConfig["builtin"]>;
testing?: Partial<WalletRunConfig["testing"]>;
features?: Partial<WalletRunConfig["features"]>;
+ lazyTaskLoop?: Partial<WalletRunConfig["lazyTaskLoop"]>;
}
```
```typescript
@@ -2987,6 +3207,15 @@ export interface WalletRunConfig {
features: {
allowHttp: boolean;
};
+ /**
+ * Start processing tasks only when explicitly required, even after
+ * init has been called.
+ *
+ * Useful when the wallet is started to make single read-only request,
+ * as otherwise wallet-core starts making network request and process
+ * unrelated pending tasks.
+ */
+ lazyTaskLoop: boolean;
}
```
```typescript
@@ -3032,9 +3261,11 @@ export interface WalletCoreVersion {
export type ScopeInfo = ScopeInfoGlobal | ScopeInfoExchange | ScopeInfoAuditor;
```
```typescript
-export type AmountString = string & {
- [__amount_str]: true;
-};
+export type AmountString =
+ | (string & {
+ [__amount_str]: true;
+ })
+ | LitAmountString;
```
```typescript
/**
@@ -3076,7 +3307,6 @@ export type Transaction =
| TransactionWithdrawal
| TransactionPayment
| TransactionRefund
- | TransactionReward
| TransactionRefresh
| TransactionDeposit
| TransactionPeerPullCredit
@@ -3149,7 +3379,6 @@ export declare enum TransactionType {
Payment = "payment",
Refund = "refund",
Refresh = "refresh",
- Reward = "reward",
Deposit = "deposit",
PeerPushDebit = "peer-push-debit",
PeerPushCredit = "peer-push-credit",
@@ -3243,6 +3472,7 @@ export declare enum TransactionMinorState {
RefundAvailable = "refund-available",
AcceptRefund = "accept-refund",
PaidByOther = "paid-by-other",
+ CompletedByOtherWallet = "completed-by-other-wallet",
}
```
```typescript
@@ -3551,17 +3781,6 @@ export interface RefundPaymentInfo {
}
```
```typescript
-export interface TransactionReward extends TransactionCommon {
- type: TransactionType.Reward;
- amountRaw: AmountString;
- /**
- * More information about the merchant
- */
- amountEffective: AmountString;
- merchantBaseUrl: string;
-}
-```
-```typescript
/**
* A transaction shown for refreshes.
* Only shown for (1) refreshes not associated with other transactions
@@ -4066,7 +4285,6 @@ export interface AddExchangeRequest {
* @deprecated use a separate API call to start a forced exchange update instead
*/
forceUpdate?: boolean;
- masterPub?: string;
}
```
```typescript