From ba9335ec4c3578fdebfbec3072396bcda29d3425 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Aug 2019 13:02:55 +0200 Subject: initial rough import of other docs --- Makefile | 9 +- api-auditor.rst | 232 ------- api-bank.rst | 392 ----------- api-common.rst | 812 ---------------------- api-error.rst | 1204 --------------------------------- api-exchange.rst | 1546 ------------------------------------------ api-merchant.rst | 1194 --------------------------------- api-sync.rst | 407 ----------- arch-api.dot | 27 + arch-api.png | Bin 0 -> 59189 bytes arch.png | Bin 0 -> 40820 bytes backoffice.rst | 155 +++++ conf.py | 1 + core/api-auditor.rst | 232 +++++++ core/api-bank.rst | 392 +++++++++++ core/api-common.rst | 812 ++++++++++++++++++++++ core/api-error.rst | 1204 +++++++++++++++++++++++++++++++++ core/api-exchange.rst | 1546 ++++++++++++++++++++++++++++++++++++++++++ core/api-merchant.rst | 1194 +++++++++++++++++++++++++++++++++ core/api-sync.rst | 407 +++++++++++ core/index.rst | 40 ++ core/taler-uri.rst | 84 +++ core/wireformats.rst | 70 ++ exchange-db-generate.sh | 3 + exchange-db.png | Bin 0 -> 564934 bytes index.rst | 29 +- merchant-api.rst | 1703 +++++++++++++++++++++++++++++++++++++++++++++++ merchant-manual.rst | 1228 ++++++++++++++++++++++++++++++++++ onboarding.rst | 386 +++++++++++ taler-bank.rst | 190 ++++++ taler-exchange.rst | 869 ++++++++++++++++++++++++ taler-uri.rst | 84 --- wireformats.rst | 70 -- 33 files changed, 10561 insertions(+), 5961 deletions(-) delete mode 100644 api-auditor.rst delete mode 100644 api-bank.rst delete mode 100644 api-common.rst delete mode 100644 api-error.rst delete mode 100644 api-exchange.rst delete mode 100644 api-merchant.rst delete mode 100644 api-sync.rst create mode 100644 arch-api.dot create mode 100644 arch-api.png create mode 100644 arch.png create mode 100644 backoffice.rst create mode 100644 core/api-auditor.rst create mode 100644 core/api-bank.rst create mode 100644 core/api-common.rst create mode 100644 core/api-error.rst create mode 100644 core/api-exchange.rst create mode 100644 core/api-merchant.rst create mode 100644 core/api-sync.rst create mode 100644 core/index.rst create mode 100644 core/taler-uri.rst create mode 100644 core/wireformats.rst create mode 100755 exchange-db-generate.sh create mode 100644 exchange-db.png create mode 100644 merchant-api.rst create mode 100644 merchant-manual.rst create mode 100644 onboarding.rst create mode 100644 taler-bank.rst create mode 100644 taler-exchange.rst delete mode 100644 taler-uri.rst delete mode 100644 wireformats.rst diff --git a/Makefile b/Makefile index f09f2a04..4b7e30a5 100644 --- a/Makefile +++ b/Makefile @@ -49,9 +49,16 @@ help: clean: rm -rf $(BUILDDIR)/* + +arch-api.png: arch-api.dot + dot -Tpng arch-api.dot > arch-api.png + +diagrams: arch-api.png + + # The html-linked builder does not support caching, so we # remove all cached state first. -html: +html: diagrams $(SPHINXBUILD) -b html-linked $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." diff --git a/api-auditor.rst b/api-auditor.rst deleted file mode 100644 index 957b1c01..00000000 --- a/api-auditor.rst +++ /dev/null @@ -1,232 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING. If not, see - - @author Christian Grothoff - -============================ -The Auditor RESTful JSON API -============================ - -The API specified here follows the :ref:`general conventions ` -for all details not specified in the individual requests. -The `glossary ` -defines all specific terms used in this section. - -.. _auditor-version: - -------------------------- -Obtaining Auditor Version -------------------------- - -This API is used by merchants to obtain a list of all exchanges audited by -this auditor. This may be required for the merchant to perform the required -know-your-customer (KYC) registration before issuing contracts. - -.. http:get:: /version - - Get the protocol version and some meta data about the auditor. - - **Response:** - - :status 200 OK: - The auditor responds with a `AuditorVersion`_ object. This request should - virtually always be successful. - - **Details:** - - .. _AuditorVersion: - .. code-block:: tsref - - interface AuditorVersion { - // libtool-style representation of the Taler protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // The format is "current:revision:age". Note that the auditor - // protocol is versioned independently of the exchange's protocol. - version: String; - - // Return which currency this auditor is auditing for. - currency: String; - - // EdDSA master public key of the auditor - auditor_public_key: EddsaPublicKey; - } - - .. note:: - - This API is still experimental (and is not yet implemented at the - time of this writing). - - -.. _exchange-list: - ------------------------ -Obtaining Exchange List ------------------------ - -This API is used by merchants to obtain a list of all exchanges audited by -this auditor. This may be required for the merchant to perform the required -know-your-customer (KYC) registration before issuing contracts. - -.. http:get:: /exchanges - - Get a list of all exchanges audited by the auditor. - - **Response:** - - :status 200 OK: - The auditor responds with a `ExchangeList`_ object. This request should - virtually always be successful. - - **Details:** - - .. _ExchangeList: - .. code-block:: tsref - - interface ExchangeList { - // Exchanges audited by this auditor - exchanges: ExchangeEntry[]; - } - - .. _tsref-type-Denom: - .. code-block:: tsref - - interface ExchangeEntry { - - // Master public key of the exchange - master_pub: EddsaPublicKey; - - // Base URL of the exchange - exchange_url: string; - } - - .. note:: - - This API is still experimental (and is not yet implemented at the - time of this writing). A key open question is whether the auditor - should sign the information. We might also want to support more - delta downloads in the future. - -.. _deposit-confirmation: - --------------------------------- -Submitting deposit confirmations --------------------------------- - -Merchants should probabilistically submit some of the deposit -confirmations they receive from the exchange to auditors to ensure -that the exchange does not lie about recording deposit confirmations -with the exchange. Participating in this scheme ensures that in case -an exchange runs into financial trouble to pay its obligations, the -merchants that did participate in detecting the bad behavior can be -paid out first. - -.. http:put:: /deposit-confirmation - - Submits a `DepositConfirmation`_ to the exchange. Should succeed - unless the signature provided is invalid or the exchange is not - audited by this auditor. - - **Response:** - - :status 200: The auditor responds with a `DepositAudited`_ object. - This request should virtually always be successful. - - **Details:** - - .. _DepositAudited: - .. _tsref-type-DepositAudited: - .. code-block:: tsref - - interface DepositAudited { - // TODO: do we care for the auditor to sign this? - } - - .. _DepositConfirmation: - .. _tsref-type-DepositConfirmation: - .. code-block:: tsref - - interface DepositConfirmation { - - // Hash over the contract for which this deposit is made. - h_contract_terms: HashCode; - - // Hash over the wiring information of the merchant. - h_wire: HashCode; - - // Time when the deposit confirmation confirmation was generated. - timestamp: Timestamp; - - // How much time does the merchant have to issue a refund - // request? Zero if refunds are not allowed. - refund_deadline : Timestamp; - - // Amount to be deposited, excluding fee. Calculated from the - // amount with fee and the fee from the deposit request. - amount_without_fee: Amount; - - // The coin's public key. This is the value that must have been - // signed (blindly) by the Exchange. The deposit request is to be - // signed by the corresponding private key (using EdDSA). - coin_pub: CoinPublicKey; - - // The Merchant's public key. Allows the merchant to later refund - // the transaction or to inquire about the wire transfer identifier. - merchant_pub: EddsaPublicKey; - - // Signature from the exchange of type - // TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT. - exchange_sig: EddsaSignature; - - // Public signing key from the exchange matching @e exchange_sig. - exchange_pub: EddsaPublicKey; - - // Master public key of the exchange corresponding to @e master_sig. - // Identifies the exchange this is about. - master_pub: EddsaPublicKey; - - // When does the validity of the exchange_pub end? - ep_start: Timestamp; - - // When will the exchange stop using the signing key? - ep_expire: Timestamp; - - // When does the validity of the exchange_pub end? - ep_end: Timestamp; - - // Exchange master signature over @e exchange_sig. - master_sig: EddsaSignature; - } - - .. note:: - - This API is still experimental (and is not yet implemented at the - time of this writing). A key open question is whether the auditor - should sign the response information. - - ----------- -Complaints ----------- - -This API is used by the wallet or merchants to submit proof of -misbehavior of an exchange to the auditor. - - .. note:: - - To be designed and implemented. - - .. http:put:: /complain - - Complain about missbehavior to the auditor. diff --git a/api-bank.rst b/api-bank.rst deleted file mode 100644 index 07de8191..00000000 --- a/api-bank.rst +++ /dev/null @@ -1,392 +0,0 @@ -.. - This file is part of GNU TALER. - - Copyright (C) 2014, 2015, 2016, 2017 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - - @author Marcello Stanisci - @author Christian Grothoff - -========= -Bank API -========= - -This API provides programmatic user registration at the bank. - -.. _bank-register: -.. http:post:: /register - -**Request** The body of this request must have the format of a `BankRegistrationRequest`_. - -**Response** - -:status 200 OK: The new user has been correctly registered. -:status 409 Conflict: the username requested by the client is not available anymore -:status 406 Not Acceptable: unacceptable characters were given for the username. See https://docs.djangoproject.com/en/2.2/ref/contrib/auth/#django.contrib.auth.models.User.username for the accepted character set. - -**Details** - -.. _BankRegistrationRequest: -.. code-block:: tsref - - interface BankRegistrationRequest { - - // Username to use for registration; max length is 150 chars. - username: string; - - // Password to associate with the username. Any characters and - // any length are valid; next releases will enforce a minimum length - // and a safer characters choice. - password: string; - } - - -This API provides programmatic withdrawal of cash via Taler to all the -users registered at the bank. It triggers a wire transfer from the client -bank account to the exchange's. - -.. _bank-register: -.. http:post:: /taler/withdraw - -**Request** The body of this request must have the format of a `BankTalerWithdrawRequest`_. - -**Response** - -:status 200 OK: The withdrawal was correctly initiated, therefore the exchange received the payment. A `BankTalerWithdrawResponse`_ object is returned. -:status 406 Not Acceptable: the user does not have sufficient credit to fulfill their request. -:status 404 Not Found: The exchange wire details did not point to any valid bank account. - -**Details** - -.. _BankTalerWithdrawRequest: -.. code-block:: tsref - - interface BankTalerWithdrawRequest { - - // Authentication method used - auth: BankAuth; - - // Amount to withdraw. - amount: Amount; - - // Reserve public key. - reserve_pub: string; - - // Exchange bank details specified in the 'payto' - // format. NOTE: this field is optional, therefore - // the bank will initiate the withdrawal with the - // default exchange, if not given. - exchange_wire_details: string; - } - -.. _BankTalerWithdrawResponse: -.. code-block:: tsref - - interface BankTalerWithdrawResponse { - - // Sender account details in 'payto' format. - sender_wire_details: string; - - // Exchange base URL. Optional: only returned - // if the user used the default exchange. - exchange_url: string; - } - -This API allows one user to send money to another user, within the same "test" -bank. The user calling it has to authenticate by including his credentials in the -request. - -.. _bank-deposit: -.. http:post:: /admin/add/incoming - -**Request:** The body of this request must have the format of a `BankDepositRequest`_. - -**Response:** - -:status 200 OK: The request has been correctly handled, so the funds have been transferred to the recipient's account. The body is a `BankDepositDetails`_. -:status 400 Bad Request: The bank replies a `BankError`_ object. -:status 406 Not Acceptable: The request had wrong currency; the bank replies a `BankError`_ object. - -**Details:** - -.. _BankDepositDetails: -.. code-block:: tsref - - interface BankDepositDetails { - - // Timestamp related to the transaction being made. - timestamp: Timestamp; - - // Row id number identifying the transaction in the bank's - // database. - row_id: number; - } - -.. _BankDepositRequest: -.. code-block:: tsref - - interface BankDepositRequest { - - // Authentication method used - auth: BankAuth; - - // JSON 'amount' object. The amount the caller wants to transfer - // to the recipient's count - amount: Amount; - - // Exchange base URL, used to perform tracking requests against the - // wire transfer ID. Note that in the actual bank wire transfer, - // the schema may have to be encoded differently, i.e. - // "https://exchange.com/" may become "https exchange.com" due to - // character set restrictions. It is the responsibility of the - // wire transfer adapter to properly encode/decode the URL. - // Payment service providers must ensure that their URL is short - // enough to fit together with the wire transfer identifier into - // the wire transfer subject of their respective banking system. - exchange_url: string; - - // The subject of this wire transfer. - subject: string; - - // The sender's account identificator. NOTE, in the current stage - // of development this field is _ignored_, as it's always the bank account - // of the logged user that plays as the "debit account". - // In future releases, a logged user may specify multiple bank accounts - // of her/his as the debit account. - debit_account: number; - - // The recipient's account identificator - credit_account: number; - - } - -.. _BankAuth: -.. _tsref-type-BankAuth: -.. code-block:: tsref - - interface BankAuth { - - // authentication type. At this stage of development, - // only value "basic" is accepted in this field. - // The credentials must be indicated in the following HTTP - // headers: "X-Taler-Bank-Username" and "X-Taler-Bank-Password". - type: string; - } - - -.. _BankError: -.. code-block:: tsref - - interface BankError { - - // Human readable explanation of the failure. - error: string; - - // Numeric Taler error code (`enum TALER_ErrorCode`) - ec: number; - - } - - -.. http:put:: /reject - - Rejects an inbound transaction. This can be used by the receiver of a wire transfer to - cancel that transaction, nullifying its effect. This basically creates a correcting - entry that voids the original transaction. Henceforth, the /history must show - the original transaction as "cancelled+" or "cancelled-" for creditor and debitor respectively. - This API is used when the exchange receives a wire transfer with an invalid wire - transfer subject that fails to decode to a public key. - - **Request** The body of this request must have the format of a `BankCancelRequest`_. - - :query auth: authentication method used. At this stage of development, only value `basic` is accepted. Note that username and password need to be given as request's headers. The dedicated headers are: `X-Taler-Bank-Username` and `X-Taler-Bank-Password`. - :query row_id: row identifier of the transaction that should be cancelled. - :query account_number: bank account for which the incoming transfer was made and for which `auth` provides the authentication data. *Currently ignored*, as multiple bank accounts per user are not implemented yet. - - .. _BankCancelRequest: - .. code-block:: tsref - - interface BankCancelRequest { - - // Authentication method used - auth: BankAuth; - - // The row id of the wire transfer to cancel - row_id: number; - - // The recipient's account identificator - credit_account: number; - - } - - **Response** In case of an error, the body is a `BankError`_ object. - - :status 204 No Content: The request has been correctly handled, so the original transaction was voided. The body is empty. - :status 400 Bad Request: The bank replies a `BankError`_ object. - :status 404 Not Found: The bank does not know this rowid for this account. - - -.. http:get:: /history-range - - Filters and returns the list of transactions in the time range specified by `start` and `end` - - **Request** - - :query auth: authentication method used. At this stage of development, only value `basic` is accepted. Note that username and password need to be given as request's headers. The dedicated headers are: `X-Taler-Bank-Username` and `X-Taler-Bank-Password`. - :query start: unix timestamp indicating the oldest transaction accepted in the result. - :query end: unix timestamp indicating the youngest transaction accepted in the result. - :query direction: argument taking values `debit` or `credit`, according to the caller willing to receive both incoming and outgoing, only outgoing, or only incoming records. Use `both` to return both directions. - :query cancelled: argument taking values `omit` or `show` to filter out rejected transactions - :query account_number: bank account whose history is to be returned. *Currently ignored*, as multiple bank accounts per user are not implemented yet. - :query ordering: can be `descending` or `ascending` and regulates whether the row are returned youger-to-older or vice versa. Defaults to `descending`. - - - **Response** - - :status 200 OK: JSON object whose field `data` is an array of type `BankTransaction`_. - :status 204 No content: in case no records exist for the targeted user. - - -.. http:get:: /history - - Filters and returns the list of transactions of the customer specified in the request. - - **Request** - - :query auth: authentication method used. At this stage of development, only value `basic` is accepted. Note that username and password need to be given as request's headers. The dedicated headers are: `X-Taler-Bank-Username` and `X-Taler-Bank-Password`. - :query delta: returns the first `N` records younger (older) than `start` if `+N` (`-N`) is specified. - :query start: according to `delta`, only those records with row id strictly greater (lesser) than `start` will be returned. This argument is optional; if not given, it defaults to "MAX_UINT64". - :query direction: argument taking values `debit` or `credit`, according to the caller willing to receive both incoming and outgoing, only outgoing, or only incoming records. Use `both` to return both directions. - :query cancelled: argument taking values `omit` or `show` to filter out rejected transactions - :query account_number: bank account whose history is to be returned. *Currently ignored*, as multiple bank accounts per user are not implemented yet. - :query ordering: can be `descending` or `ascending` and regulates whether the row are returned youger-to-older or vice versa. Defaults to `descending`. - - - **Response** - - :status 200 OK: JSON object whose field `data` is an array of type `BankTransaction`_. - :status 204 No content: in case no records exist for the targeted user. - -.. _BankTransaction: -.. code-block:: tsref - - interface BankTransaction { - - // identification number of the record - row_id: number; - - // Date of the transaction - date: Timestamp; - - // Amount transferred - amount: Amount; - - // "-" if the transfer was outgoing, "+" if it was - // incoming; "cancel+" or "cancel-" if the transfer - // was /reject-ed by the receiver. - sign: string; - - // Bank account number of the other party involved in the - // transaction. - counterpart: number; - - // Wire transfer subject line. - wt_subject: string; - - } - -.. - The counterpart currently only points to the same bank as - the client using the bank. A reasonable improvement is to - specify a bank URL too, so that Taler can run across multiple - banks. - ------------------------- -Interactions with wallet ------------------------- - -A bank and a wallet need to communicate for (1) make some elements visible -only if the wallet is installed, (2) exchange information when the user withdraws -coins. - -Make elements visible. -^^^^^^^^^^^^^^^^^^^^^^ - -This feature works via CSS injection from the wallet. To enable it, the -page must contain the ```` element, so that -the wallet will do the injection. - -Whenever a element ```` needs to be visualized (hidden) if the wallet is -installed, the special class ``taler-installed-show`` (``taler-installed-hide``) -must be added to ``x``, as follows: - -* ``y`` will make ``y`` visible. -* ``y`` will make ``y`` visible. - -Clearly, a fallback page must be provided, which will be useful if the -wallet is *not* installed. This special page will hide any element of -the class ``taler-install-show``; it can be downloaded at the following -URL: ``git://taler.net/web-common/taler-fallback.css``. - -Withdrawing coins. -^^^^^^^^^^^^^^^^^^ - -After the user confirms the withdrawal, the bank must return a `202 Accepted` response, -along with the following HTTP headers: - -* ``X-Taler-Operation: create-reserve`` -* ``X-Taler-Callback-Url: ``; this URL will be automatically visited by the wallet after the user confirms the exchange. -* ``X-Taler-Wt-Types: '["test"]'``; stringified JSON list of supported wire transfer types (only 'test' supported so far). -* ``X-Taler-Amount: ``; stringified Taler-style JSON :ref:`amount `. -* ``X-Taler-Sender-Wire: ``; stringified WireDetails_. -* ``X-Taler-Suggested-Exchange: ``; this header is optional, and ```` is the suggested exchange URL as given in the `SUGGESTED_EXCHANGE` configuration option. - -.. _WireDetails: -.. code-block:: tsref - - interface WireDetails { - type: string; // Only 'test' value admitted so far. - bank_uri: URL of the bank. - account_number: bank account number of the user attempting to withdraw. - } - -After the user confirms the exchange to withdraw coins from, the wallet will -visit the callback URL, in order to let the user answer some security questions -and provide all relevant data to create a reserve. - -.. note:: - Currently, the bank is in charge of creating the reserve at the chosen - exchange. In future, the exchange will "poll" its bank account and automatically - creating a reserve whenever it receives any funds, without any bank's - intervention. - -The callback URL implements the following API. - -.. http:get:: - - **Request** - - :query amount_value: integer part of the amount to be withdrawn. - :query amount_fraction: fractional part of the amount to be withdrawn. - :query amount_currency: currency of the amount to be withdrawn. - :query exchange: base URL of the exchange where the reserve is to be created. - :query reserve_pub: public key of the reserve to create. - :query exchange_wire_details: stringification of the chosen exchange's WireDetails_. - - **Response** - - Because the wallet is not supposed to take action according to this response, - the bank implementers are not required to return any particular status code here. - - For example, our demonstrator bank always redirects the browser to the user's - profile page and let them know the outcome via a informational bar. diff --git a/api-common.rst b/api-common.rst deleted file mode 100644 index 8f3ae378..00000000 --- a/api-common.rst +++ /dev/null @@ -1,812 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014, 2015, 2016 GNUnet e.V. and INRIA - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING. If not, see - - @author Christian Grothoff - @author Marcello Stanisci - -.. _http-common: - -================================= -Common Taler HTTP API Conventions -================================= - - -------------------------- -HTTP Request and Response -------------------------- - -Certain response formats are common for all requests. They are documented here -instead of with each individual request. Furthermore, we note that clients may -theoretically fail to receive any response. In this case, the client should -verify that the Internet connection is working properly, and then proceed to -handle the error as if an internal error (500) had been returned. - -.. http:any:: /* - - - **Request:** - - Unless specified otherwise, HTTP requests that carry a message body must - have the content type `application/json`. - - :reqheader Content-Type: application/json - - **Response:** - - :resheader Content-Type: application/json - :status 200: The request was successful. - :status 500 Internal server error: - This always indicates some serious internal operational error of the exchange, - such as a program bug, database problems, etc., and must not be used for - client-side problems. When facing an internal server error, clients should - retry their request after some delay. We recommended initially trying after - 1s, twice more at randomized times within 1 minute, then the user should be - informed and another three retries should be scheduled within the next 24h. - If the error persists, a report should ultimately be made to the auditor, - although the auditor API for this is not yet specified. However, as internal - server errors are always reported to the exchange operator, a good operator - should naturally be able to address them in a timely fashion, especially - within 24h. When generating an internal server error, the exchange responds with - a JSON object containing the following fields: - :status 400 Bad Request: One of the arguments to the request is missing or malformed. - - Unless specified otherwise, all error status codes (4xx and 5xx) have a message - body with an `ErrorDetail`_ JSON object. - - **Details:** - - .. _ErrorDetail: - .. _tsref-type-ErrorDetail: - .. code-block:: tsref - - interface ErrorDetail { - - // Numeric `error code `_ unique to the condition. - code: number; - - // Human-readable description of the error, i.e. "missing parameter", "commitment violation", ... - // The other arguments are specific to the error value reported here. - error: string; - - // Hint about error nature - hint?: string; - - // Name of the parameter that was bogus (if applicable) - parameter?: string; - - // Path to the argument that was bogus (if applicable) - path?: string; - - // Offset of the argument that was bogus (if applicable) - offset?: string; - - // Index of the argument that was bogus (if applicable) - index?: string; - - // Name of the object that was bogus (if applicable) - object?: string; - - // Name of the currency thant was problematic (if applicable) - currency?: string; - - // Expected type (if applicable). - type_expected?: string; - - // Type that was provided instead (if applicable). - type_actual?: string; - } - - -.. _encodings-ref: - ----------------- -Common encodings ----------------- - -This section describes how certain types of values are represented throughout the API. - -.. _base32: -.. _tsref-type-Base32: - -Binary Data -^^^^^^^^^^^ - -Binary data is generally encoded using Crockford's variant of Base32 -(http://www.crockford.com/wrmg/base32.html), except that "U" is not excluded -but also decodes to "V" to make OCR easy. We will still simply use the JSON -type "base32" and the term "Crockford Base32" in the text to refer to the -resulting encoding. - -.. _tsref-type-HashCode: - -Hash codes -^^^^^^^^^^ -Hashcodes are strings representing base32 encoding of the respective hashed -data. See `base32`_. - -Large numbers -^^^^^^^^^^^^^ - -Large numbers such as RSA blinding factors and 256 bit keys, are transmitted -as other binary data in Crockford Base32 encoding. - - -.. _tsref-type-Timestamp: - -Timestamps -^^^^^^^^^^ - -Timestamps are represented in JSON as a string literal `"\\/Date(x)\\/"`, -where `x` is the decimal representation of the number of seconds past the -Unix Epoch (January 1, 1970). The escaped slash (`\\/`) is interpreted in -JSON simply as a normal slash, but distinguishes the timestamp from a normal -string literal. We use the type "date" in the documentation below. -Additionally, the special strings "\\/never\\/" and "\\/forever\\/" are -recognized to represent the end of time. - - -.. _public\ key: - -Keys -^^^^ - -.. _`tsref-type-EddsaPublicKey`: -.. _`tsref-type-EcdhePublicKey`: -.. _`tsref-type-EcdhePrivateKey`: -.. _`tsref-type-EddsaPrivateKey`: -.. _`tsref-type-CoinPublicKey`: - -.. code-block:: tsref - - // EdDSA and ECDHE public keys always point on Curve25519 - // and represented using the standard 256 bits Ed25519 compact format, - // converted to Crockford `Base32`_. - type EddsaPublicKey = string; - type EddsaPrivateKey = string; - -.. _`tsref-type-RsaPublicKey`: - -.. code-block:: tsref - - // RSA public key converted to Crockford `Base32`_. - type RsaPublicKey = string; - -.. _blinded-coin: - -Blinded coin -^^^^^^^^^^^^ - -.. _`tsref-type-CoinEnvelope`: - -.. code-block:: tsref - - // Blinded coin's `public EdDSA key `_, `base32`_ encoded - type CoinEnvelope = string; - -.. _signature: - -Signatures -^^^^^^^^^^ - -.. _`tsref-type-EddsaSignature`: - -.. code-block:: tsref - - // EdDSA signatures are transmitted as 64-bytes `base32`_ - // binary-encoded objects with just the R and S values (base32_ binary-only) - type EddsaSignature = string; - - -.. _`tsref-type-RsaSignature`: - -.. code-block:: tsref - - // `base32`_ encoded RSA signature - type RsaSignature = string; - -.. _`tsref-type-BlindedRsaSignature`: - -.. code-block:: tsref - - // `base32`_ encoded RSA blinded signature - type BlindedRsaSignature = string; - -.. _amount: - -Amounts -^^^^^^^ - -.. _`tsref-type-Amount`: - -Amounts of currency are serialized as a string of the format `:`. -Taler treats monetary amounts as fixed-precision numbers. Unlike floating point numbers, -this allows accurate representation of monetary amounts. - -The following constrains apply for a valid amount: - -1. The `` part must be at most 12 characters long and may not contain a colon (`:`). -2. The integer part of `` may be at most 2^52 -3. the fractional part of `` may contain at most 8 decimal digits. - -Internally, amounts are parsed into the following object: - -.. note:: - - "EUR:1.50" and "EUR:10" are is a valid amounts. These are all invalid amounts: "A:B:1.5", "EUR:4503599627370501.0", "EUR:1.", "EUR:.1" - -.. code-block:: tsref - - interface ParsedAmount { - // name of the currency using either a three-character ISO 4217 currency - // code, or a regional currency identifier starting with a "*" followed by - // at most 10 characters. ISO 4217 exponents in the name are not supported, - // although the "fraction" is corresponds to an ISO 4217 exponent of 6. - currency: string; - - // unsigned 32 bit value in the currency, note that "1" here would - // correspond to 1 EUR or 1 USD, depending on `currency`, not 1 cent. - value: number; - - // unsigned 32 bit fractional value to be added to `value` representing - // an additional currency fraction, in units of one millionth (1e-6) - // of the base currency value. For example, a fraction - // of 500,000 would correspond to 50 cents. - fraction: number; - } - - --------------- -Binary Formats --------------- - - .. note:: - - Due to the way of handling `big` numbers by some platforms (such as - `JavaScript`, for example), wherever the following specification mentions - a 64-bit value, the actual implementations are strongly advised to rely on - arithmetic up to 53 bits. - - .. note:: - - Taler uses `libgnunetutil` for interfacing itself with the operating system, - doing crypto work, and other "low level" actions, therefore it is strongly - connected with the `GNUnet project `_. - -This section specifies the binary representation of messages used in Taler's -protocols. The message formats are given in a C-style pseudocode notation. -Padding is always specified explicitly, and numeric values are in network byte -order (big endian). - -Amounts -^^^^^^^ - -Amounts of currency are always expressed in terms of a base value, a fractional -value and the denomination of the currency: - -.. sourcecode:: c - - struct TALER_Amount { - uint64_t value; - uint32_t fraction; - uint8_t currency_code[12]; // i.e. "EUR" or "USD" - }; - struct TALER_AmountNBO { - uint64_t value; // in network byte order - uint32_t fraction; // in network byte order - uint8_t currency_code[12]; - }; - - -Time -^^^^ - -In signed messages, time is represented using 64-bit big-endian values, -denoting microseconds since the UNIX Epoch. `UINT64_MAX` represents "never". - -.. sourcecode:: c - - struct GNUNET_TIME_Absolute { - uint64_t timestamp_us; - }; - struct GNUNET_TIME_AbsoluteNBO { - uint64_t abs_value_us__; // in network byte order - }; - -Cryptographic primitives -^^^^^^^^^^^^^^^^^^^^^^^^ - -All elliptic curve operations are on Curve25519. Public and private keys are -thus 32 bytes, and signatures 64 bytes. For hashing, including HKDFs, Taler -uses 512-bit hash codes (64 bytes). - -.. sourcecode:: c - - struct GNUNET_HashCode { - uint8_t hash[64]; // usually SHA-512 - }; - -.. _reserve-pub: -.. sourcecode:: c - - struct TALER_ReservePublicKeyP { - uint8_t eddsa_pub[32]; - }; - -.. _reserve-priv: -.. sourcecode:: c - - struct TALER_ReservePrivateKeyP { - uint8_t eddsa_priv[32]; - }; - - struct TALER_ReserveSignatureP { - uint8_t eddsa_signature[64]; - }; - -.. _merchant-pub: -.. sourcecode:: c - - struct TALER_MerchantPublicKeyP { - uint8_t eddsa_pub[32]; - }; - - struct TALER_MerchantPrivateKeyP { - uint8_t eddsa_priv[32]; - }; - - struct TALER_TransferPublicKeyP { - uint8_t ecdhe_pub[32]; - }; - - struct TALER_TransferPrivateKeyP { - uint8_t ecdhe_priv[32]; - }; - -.. _sign-key-pub: -.. sourcecode:: c - - struct TALER_ExchangePublicKeyP { - uint8_t eddsa_pub[32]; - }; - -.. _sign-key-priv: -.. sourcecode:: c - - struct TALER_ExchangePrivateKeyP { - uint8_t eddsa_priv[32]; - }; - -.. _eddsa-sig: -.. sourcecode:: c - - struct TALER_ExchangeSignatureP { - uint8_t eddsa_signature[64]; - }; - - struct TALER_MasterPublicKeyP { - uint8_t eddsa_pub[32]; - }; - - struct TALER_MasterPrivateKeyP { - uint8_t eddsa_priv[32]; - }; - - struct TALER_MasterSignatureP { - uint8_t eddsa_signature[64]; - }; - -.. _eddsa-coin-pub: -.. sourcecode:: c - - union TALER_CoinSpendPublicKeyP { - uint8_t eddsa_pub[32]; - uint8_t ecdhe_pub[32]; - }; - -.. _coin-priv: -.. sourcecode:: c - - union TALER_CoinSpendPrivateKeyP { - uint8_t eddsa_priv[32]; - uint8_t ecdhe_priv[32]; - }; - - struct TALER_CoinSpendSignatureP { - uint8_t eddsa_signature[64]; - }; - - struct TALER_TransferSecretP { - uint8_t key[sizeof (struct GNUNET_HashCode)]; - }; - uint8_t key[sizeof (struct GNUNET_HashCode)]; - }; - - struct TALER_EncryptedLinkSecretP { - uint8_t enc[sizeof (struct TALER_LinkSecretP)]; - }; - -.. _Signatures: - -Signatures -^^^^^^^^^^ -Any piece of signed data, complies to the abstract data structure given below. - -.. sourcecode:: c - - struct Data { - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - type1_t payload1; - type2_t payload2; - ... - }; - - /*From gnunet_crypto_lib.h*/ - struct GNUNET_CRYPTO_EccSignaturePurpose { - /** - - The following constrains apply for a valid amount: - - * asd - * This field is used to express the context in - * which the signature is made, ensuring that a - * signature cannot be lifted from one part of the protocol - * to another. See `src/include/taler_signatures.h` within the - * exchange's codebase (git://taler.net/exchange) - */ - uint32_t purpose; - /** - * This field equals the number of bytes being signed, - * namely 'sizeof (struct Data)' - */ - uint32_t size; - }; - - -The following list contains all the data structure that can be signed in -Taler. Their definition is typically found in `src/include/taler_signatures.h`, -within the -`exchange's codebase `_. - -.. _TALER_WithdrawRequestPS: -.. sourcecode:: c - - struct TALER_WithdrawRequestPS { - /** - * purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct TALER_ReservePublicKeyP reserve_pub; - struct TALER_AmountNBO amount_with_fee; - struct TALER_AmountNBO withdraw_fee; - struct GNUNET_HashCode h_denomination_pub; - struct GNUNET_HashCode h_coin_envelope; - }; - -.. _TALER_DepositRequestPS: -.. sourcecode:: c - - struct TALER_DepositRequestPS { - /** - * purpose.purpose = TALER_SIGNATURE_WALLET_COIN_DEPOSIT - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode h_contract_terms; - struct GNUNET_HashCode h_wire; - struct GNUNET_TIME_AbsoluteNBO timestamp; - struct GNUNET_TIME_AbsoluteNBO refund_deadline; - struct TALER_AmountNBO amount_with_fee; - struct TALER_AmountNBO deposit_fee; - struct TALER_MerchantPublicKeyP merchant; - union TALER_CoinSpendPublicKeyP coin_pub; - }; - -.. _TALER_DepositConfirmationPS: -.. sourcecode:: c - - struct TALER_DepositConfirmationPS { - /** - * purpose.purpose = TALER_SIGNATURE_WALLET_CONFIRM_DEPOSIT - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode h_contract_terms; - struct GNUNET_HashCode h_wire; - struct GNUNET_TIME_AbsoluteNBO timestamp; - struct GNUNET_TIME_AbsoluteNBO refund_deadline; - struct TALER_AmountNBO amount_without_fee; - union TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_MerchantPublicKeyP merchant; - }; - -.. _TALER_RefreshMeltCoinAffirmationPS: -.. sourcecode:: c - - struct TALER_RefreshMeltCoinAffirmationPS { - /** - * purpose.purpose = TALER_SIGNATURE_WALLET_COIN_MELT - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode session_hash; - struct TALER_AmountNBO amount_with_fee; - struct TALER_AmountNBO melt_fee; - union TALER_CoinSpendPublicKeyP coin_pub; - }; - -.. _TALER_RefreshMeltConfirmationPS: -.. sourcecode:: c - - struct TALER_RefreshMeltConfirmationPS { - /** - * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode session_hash; - uint16_t noreveal_index; - }; - -.. _TALER_ExchangeSigningKeyValidityPS: -.. sourcecode:: c - - struct TALER_ExchangeSigningKeyValidityPS { - /** - * purpose.purpose = TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct TALER_MasterPublicKeyP master_public_key; - struct GNUNET_TIME_AbsoluteNBO start; - struct GNUNET_TIME_AbsoluteNBO expire; - struct GNUNET_TIME_AbsoluteNBO end; - struct TALER_ExchangePublicKeyP signkey_pub; - }; - - struct TALER_ExchangeKeySetPS { - /** - * purpose.purpose = TALER_SIGNATURE_EXCHANGE_KEY_SET - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_TIME_AbsoluteNBO list_issue_date; - struct GNUNET_HashCode hc; - }; - -.. _TALER_DenominationKeyValidityPS: -.. sourcecode:: c - - struct TALER_DenominationKeyValidityPS { - /** - * purpose.purpose = TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct TALER_MasterPublicKeyP master; - struct GNUNET_TIME_AbsoluteNBO start; - struct GNUNET_TIME_AbsoluteNBO expire_withdraw; - struct GNUNET_TIME_AbsoluteNBO expire_spend; - struct GNUNET_TIME_AbsoluteNBO expire_legal; - struct TALER_AmountNBO value; - struct TALER_AmountNBO fee_withdraw; - struct TALER_AmountNBO fee_deposit; - struct TALER_AmountNBO fee_refresh; - struct GNUNET_HashCode denom_hash; - }; - -.. _TALER_MasterWireDetailsPS: -.. sourcecode:: c - - struct TALER_MasterWireDetailsPS { - /** - * purpose.purpose = TALER_SIGNATURE_MASTER_WIRE_DETAILS - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode h_wire_details; - }; - - -.. _TALER_MasterWireFeePS: -.. sourcecode:: c - - struct TALER_MasterWireFeePS { - /** - * purpose.purpose = TALER_SIGNATURE_MASTER_WIRE_FEES - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode h_wire_method; - struct GNUNET_TIME_AbsoluteNBO start_date; - struct GNUNET_TIME_AbsoluteNBO end_date; - struct TALER_AmountNBO wire_fee; - struct TALER_AmountNBO closing_fee; - }; - -.. _TALER_DepositTrackPS: -.. sourcecode:: c - - struct TALER_DepositTrackPS { - /** - * purpose.purpose = TALER_SIGNATURE_MASTER_SEPA_DETAILS || TALER_SIGNATURE_MASTER_TEST_DETAILS - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode h_contract_terms; - struct GNUNET_HashCode h_wire; - struct TALER_MerchantPublicKeyP merchant; - struct TALER_CoinSpendPublicKeyP coin_pub; - }; - -.. _TALER_WireDepositDetailP: -.. sourcecode:: c - - struct TALER_WireDepositDetailP { - struct GNUNET_HashCode h_contract_terms; - struct GNUNET_TIME_AbsoluteNBO execution_time; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_AmountNBO deposit_value; - struct TALER_AmountNBO deposit_fee; - }; - - -.. _TALER_WireDepositDataPS: -.. sourcecode:: c - - struct TALER_WireDepositDataPS { - /** - * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct TALER_AmountNBO total; - struct TALER_AmountNBO wire_fee; - struct TALER_MerchantPublicKeyP merchant_pub; - struct GNUNET_HashCode h_wire; - struct GNUNET_HashCode h_details; - }; - -.. _TALER_ExchangeKeyValidityPS: -.. sourcecode:: c - - struct TALER_ExchangeKeyValidityPS { - /** - * purpose.purpose = TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode auditor_url_hash; - struct TALER_MasterPublicKeyP master; - struct GNUNET_TIME_AbsoluteNBO start; - struct GNUNET_TIME_AbsoluteNBO expire_withdraw; - struct GNUNET_TIME_AbsoluteNBO expire_spend; - struct GNUNET_TIME_AbsoluteNBO expire_legal; - struct TALER_AmountNBO value; - struct TALER_AmountNBO fee_withdraw; - struct TALER_AmountNBO fee_deposit; - struct TALER_AmountNBO fee_refresh; - struct GNUNET_HashCode denom_hash; - }; - -.. _TALER_PaymentResponsePS: -.. sourcecode:: c - - struct PaymentResponsePS { - /** - * purpose.purpose = TALER_SIGNATURE_MERCHANT_PAYMENT_OK - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode h_contract_terms; - }; - -.. _TALER_ContractPS: -.. sourcecode:: c - - struct TALER_ContractPS { - /** - * purpose.purpose = TALER_SIGNATURE_MERCHANT_CONTRACT - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct TALER_AmountNBO total_amount; - struct TALER_AmountNBO max_fee; - struct GNUNET_HashCode h_contract_terms; - struct TALER_MerchantPublicKeyP merchant_pub; - }; - -.. _TALER_ConfirmWirePS: -.. sourcecode:: c - - struct TALER_ConfirmWirePS { - /** - * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode h_wire; - struct GNUNET_HashCode h_contract_terms; - struct TALER_WireTransferIdentifierRawP wtid; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct GNUNET_TIME_AbsoluteNBO execution_time; - struct TALER_AmountNBO coin_contribution; - }; - -.. _TALER_RefundRequestPS: -.. sourcecode:: c - - struct TALER_RefundRequestPS { - /** - * purpose.purpose = TALER_SIGNATURE_MERCHANT_REFUND - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode h_contract_terms; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_MerchantPublicKeyP merchant; - uint64_t rtransaction_id; - struct TALER_AmountNBO refund_amount; - struct TALER_AmountNBO refund_fee; - }; - - struct TALER_MerchantRefundConfirmationPS { - /** - * purpose.purpose = TALER_SIGNATURE_MERCHANT_REFUND_OK - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - /** - * Hash of the order ID (a string), hashed without the 0-termination. - */ - struct GNUNET_HashCode h_order_id; - }; - - -.. _TALER_PaybackRequestPS: -.. sourcecode:: c - - struct TALER_PaybackRequestPS { - /** - * purpose.purpose = TALER_SIGNATURE_WALLET_COIN_PAYBACK - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct GNUNET_HashCode h_denom_pub; - struct TALER_DenominationBlindingKeyP coin_blind; - }; - - -.. _TALER_PaybackConfirmationPS: -.. sourcecode:: c - - struct TALER_PaybackConfirmationPS { - /** - * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_TIME_AbsoluteNBO timestamp; - struct TALER_AmountNBO payback_amount; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_ReservePublicKeyP reserve_pub; - }; - - -.. _TALER_ReserveCloseConfirmationPS: -.. sourcecode:: c - - struct TALER_ReserveCloseConfirmationPS { - /** - * purpose.purpose = TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_TIME_AbsoluteNBO timestamp; - struct TALER_AmountNBO closing_amount; - struct TALER_ReservePublicKeyP reserve_pub; - struct GNUNET_HashCode h_wire; - }; - -.. _TALER_CoinLinkSignaturePS: -.. sourcecode:: c - - struct TALER_CoinLinkSignaturePS { - /** - * purpose.purpose = TALER_SIGNATURE_WALLET_COIN_LINK - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode h_denom_pub; - struct TALER_CoinSpendPublicKeyP old_coin_pub; - struct TALER_TransferPublicKeyP transfer_pub; - struct GNUNET_HashCode coin_envelope_hash; - }; diff --git a/api-error.rst b/api-error.rst deleted file mode 100644 index 61716b72..00000000 --- a/api-error.rst +++ /dev/null @@ -1,1204 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014, 2015, 2016 GNUnet e.V. and INRIA - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING. If not, see - - @author Marcello Stanisci - -.. - The reason to have a dedicate page for error codes was due to a buggy - behaviour in pages cross-linking: was not possible from other pages to - reference the '_error-codes' label (see just below) if we kept in api-common.rst - (which is the best place to place this error codes list). - ------------ -Error Codes ------------ - -The following list shows error codes defined in -`/src/include/taler_error_codes.h `_ - -.. _error-codes: -.. code-block:: c - - /** - * Enumeration with all possible Taler error codes. - */ - enum TALER_ErrorCode { - - /** - * Special code to indicate no error (or no "code" present). - */ - TALER_EC_NONE = 0, - - /** - * Special code to indicate that a non-integer error code was - * returned in the JSON response. - */ - TALER_EC_INVALID = 1, - - /** - * The response we got from the server was not even in JSON format. - */ - TALER_EC_INVALID_RESPONSE = 2, - - /** - * Generic implementation error: this function was not yet implemented. - */ - TALER_EC_NOT_IMPLEMENTED = 3, - - /* ********** generic error codes ************* */ - - /** - * The exchange failed to even just initialize its connection to the - * database. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_DB_SETUP_FAILED = 1001, - - /** - * The exchange encountered an error event to just start - * the database transaction. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_DB_START_FAILED = 1002, - - /** - * The exchange encountered an error event to commit - * the database transaction (hard, unrecoverable error). - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_DB_COMMIT_FAILED_HARD = 1003, - - /** - * The exchange encountered an error event to commit - * the database transaction, even after repeatedly - * retrying it there was always a conflicting transaction. - * (This indicates a repeated serialization error; should - * only happen if some client maliciously tries to create - * conflicting concurrent transactions.) - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_DB_COMMIT_FAILED_ON_RETRY = 1004, - - /** - * The exchange had insufficient memory to parse the request. This - * response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_PARSER_OUT_OF_MEMORY = 1005, - - /** - * The JSON in the client's request to the exchange was malformed. - * (Generic parse error). - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_JSON_INVALID = 1006, - - /** - * The JSON in the client's request to the exchange was malformed. - * Details about the location of the parse error are provided. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_JSON_INVALID_WITH_DETAILS = 1007, - - /** - * A required parameter in the request to the exchange was missing. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PARAMETER_MISSING = 1008, - - /** - * A parameter in the request to the exchange was malformed. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PARAMETER_MALFORMED = 1009, - - /* ********** request-specific error codes ************* */ - - /** - * The given reserve does not have sufficient funds to admit the - * requested withdraw operation at this time. The response includes - * the current "balance" of the reserve as well as the transaction - * "history" that lead to this balance. This response is provided - * with HTTP status code MHD_HTTP_FORBIDDEN. - */ - TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS = 1100, - - /** - * The exchange has no information about the "reserve_pub" that - * was given. - * This response is provided with HTTP status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_WITHDRAW_RESERVE_UNKNOWN = 1101, - - /** - * The amount to withdraw together with the fee exceeds the - * numeric range for Taler amounts. This is not a client - * failure, as the coin value and fees come from the exchange's - * configuration. - * This response is provided with HTTP status code MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW = 1102, - - /** - * All of the deposited amounts into this reserve total up to a - * value that is too big for the numeric range for Taler amounts. - * This is not a client failure, as the transaction history comes - * from the exchange's configuration. This response is provided - * with HTTP status code MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_WITHDRAW_AMOUNT_DEPOSITS_OVERFLOW = 1103, - - /** - * For one of the historic withdrawals from this reserve, the - * exchange could not find the denomination key. - * This is not a client failure, as the transaction history comes - * from the exchange's configuration. This response is provided - * with HTTP status code MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_WITHDRAW_HISTORIC_DENOMINATION_KEY_NOT_FOUND = 1104, - - /** - * All of the withdrawals from reserve total up to a - * value that is too big for the numeric range for Taler amounts. - * This is not a client failure, as the transaction history comes - * from the exchange's configuration. This response is provided - * with HTTP status code MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_WITHDRAW_AMOUNT_WITHDRAWALS_OVERFLOW = 1105, - - /** - * The exchange somehow knows about this reserve, but there seem to - * have been no wire transfers made. This is not a client failure, - * as this is a database consistency issue of the exchange. This - * response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_WITHDRAW_RESERVE_WITHOUT_WIRE_TRANSFER = 1106, - - /** - * The exchange failed to create the signature using the - * denomination key. This response is provided with HTTP status - * code MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_WITHDRAW_SIGNATURE_FAILED = 1107, - - /** - * The exchange failed to store the withdraw operation in its - * database. This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_WITHDRAW_DB_STORE_ERROR = 1108, - - /** - * The exchange failed to check against historic withdraw data from - * database (as part of ensuring the idempotency of the operation). - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_WITHDRAW_DB_FETCH_ERROR = 1109, - - /** - * The exchange is not aware of the denomination key - * the wallet requested for the withdrawal. - * This response is provided - * with HTTP status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND = 1110, - - /** - * The signature of the reserve is not valid. This response is - * provided with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_WITHDRAW_RESERVE_SIGNATURE_INVALID = 1111, - - /** - * The exchange failed to obtain the transaction history of the - * given reserve from the database while generating an insufficient - * funds errors. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1112, - - /** - * When computing the reserve history, we ended up with a negative - * overall balance, which should be impossible. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_WITHDRAW_RESERVE_HISTORY_IMPOSSIBLE = 1113, - - /** - * The exchange failed to obtain the transaction history of the - * given reserve from the database. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_RESERVE_STATUS_DB_ERROR = 1150, - - - /** - * The respective coin did not have sufficient residual value - * for the /deposit operation (i.e. due to double spending). - * The "history" in the respose provides the transaction history - * of the coin proving this fact. This response is provided - * with HTTP status code MHD_HTTP_FORBIDDEN. - */ - TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS = 1200, - - /** - * The exchange failed to obtain the transaction history of the - * given coin from the database (this does not happen merely because - * the coin is seen by the exchange for the first time). - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_DEPOSIT_HISTORY_DB_ERROR = 1201, - - /** - * The exchange failed to store the /depost information in the - * database. This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_DEPOSIT_STORE_DB_ERROR = 1202, - - /** - * The exchange database is unaware of the denomination key that - * signed the coin (however, the exchange process is; this is not - * supposed to happen; it can happen if someone decides to purge the - * DB behind the back of the exchange process). Hence the deposit - * is being refused. This response is provided with HTTP status - * code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_DEPOSIT_DB_DENOMINATION_KEY_UNKNOWN = 1203, - - /** - * The exchange database is unaware of the denomination key that - * signed the coin (however, the exchange process is; this is not - * supposed to happen; it can happen if someone decides to purge the - * DB behind the back of the exchange process). Hence the deposit - * is being refused. This response is provided with HTTP status - * code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_DEPOSIT_DENOMINATION_KEY_UNKNOWN = 1204, - - /** - * The signature of the coin is not valid. This response is - * provided with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID = 1205, - - /** - * The signature of the denomination key over the coin is not valid. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_DEPOSIT_DENOMINATION_SIGNATURE_INVALID = 1206, - - /** - * The stated value of the coin after the deposit fee is subtracted - * would be negative. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE = 1207, - - /** - * The stated refund deadline is after the wire deadline. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE = 1208, - - /** - * The exchange does not recognize the validity of or support the - * given wire format type. - * This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE = 1209, - - /** - * The exchange failed to canonicalize and hash the given wire format. - * This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON = 1210, - - /** - * The hash of the given wire address does not match the hash - * specified in the contract. - * This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT = 1211, - - /** - * The exchange failed to obtain the transaction history of the - * given coin from the database while generating an insufficient - * funds errors. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_DEPOSIT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1212, - - /** - * The exchange detected that the given account number - * is invalid for the selected wire format type. - * This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_ACCOUNT_NUMBER = 1213, - - /** - * The signature over the given wire details is invalid. - * This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE = 1214, - - /** - * The bank specified in the wire transfer format is not supported - * by this exchange. - * This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_BANK = 1215, - - /** - * No wire format type was specified in the JSON wire format - * details. - * This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_MISSING = 1216, - - /** - * The given wire format type is not supported by this - * exchange. - * This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_UNSUPPORTED = 1217, - - - /** - * The respective coin did not have sufficient residual value - * for the /refresh/melt operation. The "history" in this - * response provdes the "residual_value" of the coin, which may - * be less than its "original_value". This response is provided - * with HTTP status code MHD_HTTP_FORBIDDEN. - */ - TALER_EC_REFRESH_MELT_INSUFFICIENT_FUNDS = 1300, - - /** - * The exchange is unaware of the denomination key that was - * used to sign the melted coin. This response is provided - * with HTTP status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND = 1301, - - /** - * The exchange had an internal error reconstructing the - * transaction history of the coin that was being melted. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_REFRESH_MELT_COIN_HISTORY_COMPUTATION_FAILED = 1302, - - /** - * The exchange failed to check against historic melt data from - * database (as part of ensuring the idempotency of the operation). - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_REFRESH_MELT_DB_FETCH_ERROR = 1303, - - /** - * The exchange failed to store session data in the - * database. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR = 1304, - - /** - * The exchange failed to store refresh order data in the - * database. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_REFRESH_MELT_DB_STORE_ORDER_ERROR = 1305, - - /** - * The exchange failed to store commit data in the - * database. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_REFRESH_MELT_DB_STORE_COMMIT_ERROR = 1306, - - /** - * The exchange failed to store transfer keys in the - * database. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_REFRESH_MELT_DB_STORE_TRANSFER_ERROR = 1307, - - /** - * The exchange is unaware of the denomination key that was - * requested for one of the fresh coins. This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFRESH_MELT_FRESH_DENOMINATION_KEY_NOT_FOUND = 1308, - - /** - * The exchange encountered a numeric overflow totaling up - * the cost for the refresh operation. This response is provided - * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_REFRESH_MELT_COST_CALCULATION_OVERFLOW = 1309, - - /** - * During the transaction phase, the exchange could suddenly - * no longer find the denomination key that was - * used to sign the melted coin. This response is provided - * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_REFRESH_MELT_DB_DENOMINATION_KEY_NOT_FOUND = 1310, - - /** - * The exchange encountered melt fees exceeding the melted - * coin's contribution. This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION = 1311, - - /** - * The exchange's cost calculation does not add up to the - * melt fees specified in the request. This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFRESH_MELT_FEES_MISSMATCH = 1312, - - /** - * The denomination key signature on the melted coin is invalid. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID = 1313, - - /** - * The exchange's cost calculation shows that the melt amount - * is below the costs of the transaction. This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFRESH_MELT_AMOUNT_INSUFFICIENT = 1314, - - /** - * The signature made with the coin to be melted is invalid. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFRESH_MELT_COIN_SIGNATURE_INVALID = 1315, - - /** - * The size of the cut-and-choose dimension of the - * blinded coins request does not match #TALER_CNC_KAPPA. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFRESH_MELT_CNC_COIN_ARRAY_SIZE_INVALID = 1316, - - /** - * The size of the cut-and-choose dimension of the - * transfer keys request does not match #TALER_CNC_KAPPA. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFRESH_MELT_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1317, - - /** - * The exchange failed to obtain the transaction history of the - * given coin from the database while generating an insufficient - * funds errors. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_REFRESH_MELT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1318, - - /** - * The provided transfer keys do not match up with the - * original commitment. Information about the original - * commitment is included in the response. This response is - * provided with HTTP status code MHD_HTTP_CONFLICT. - */ - TALER_EC_REFRESH_REVEAL_COMMITMENT_VIOLATION = 1350, - - /** - * Failed to blind the envelope to reconstruct the blinded - * coins for revealation checks. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_REFRESH_REVEAL_BLINDING_ERROR = 1351, - - /** - * Failed to produce the blinded signatures over the coins - * to be returned. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_REFRESH_REVEAL_SIGNING_ERROR = 1352, - - /** - * The exchange is unaware of the refresh sessino specified in - * the request. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN = 1353, - - /** - * The exchange failed to retrieve valid session data from the - * database. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR = 1354, - - /** - * The exchange failed to retrieve order data from the - * database. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR = 1355, - - /** - * The exchange failed to retrieve transfer keys from the - * database. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_REFRESH_REVEAL_DB_FETCH_TRANSFER_ERROR = 1356, - - /** - * The exchange failed to retrieve commitment data from the - * database. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. - */ - TALER_EC_REFRESH_REVEAL_DB_FETCH_COMMIT_ERROR = 1357, - - /** - * The size of the cut-and-choose dimension of the - * private transfer keys request does not match #TALER_CNC_KAPPA - 1. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFRESH_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1358, - - - /** - * The coin specified in the link request is unknown to the exchange. - * This response is provided with HTTP status code - * MHD_HTTP_NOT_FOUND. - */ - TALER_EC_REFRESH_LINK_COIN_UNKNOWN = 1400, - - - /** - * The exchange knows literally nothing about the coin we were asked - * to refund. But without a transaction history, we cannot issue a - * refund. This is kind-of OK, the owner should just refresh it - * directly without executing the refund. This response is provided - * with HTTP status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_REFUND_COIN_NOT_FOUND = 1500, - - /** - * We could not process the refund request as the coin's transaction - * history does not permit the requested refund at this time. The - * "history" in the response proves this. This response is provided - * with HTTP status code MHD_HTTP_CONFLICT. - */ - TALER_EC_REFUND_CONFLICT = 1501, - - /** - * The exchange knows about the coin we were asked to refund, but - * not about the specific /deposit operation. Hence, we cannot - * issue a refund (as we do not know if this merchant public key is - * authorized to do a refund). This response is provided with HTTP - * status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_REFUND_DEPOSIT_NOT_FOUND = 1503, - - /** - * The currency specified for the refund is different from - * the currency of the coin. This response is provided with HTTP - * status code MHD_HTTP_PRECONDITION_FAILED. - */ - TALER_EC_REFUND_CURRENCY_MISSMATCH = 1504, - - /** - * When we tried to check if we already paid out the coin, the - * exchange's database suddenly disagreed with data it previously - * provided (internal inconsistency). - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_REFUND_DB_INCONSISTENT = 1505, - - /** - * The exchange can no longer refund the customer/coin as the - * money was already transferred (paid out) to the merchant. - * (It should be past the refund deadline.) - * This response is provided with HTTP status code - * MHD_HTTP_GONE. - */ - TALER_EC_REFUND_MERCHANT_ALREADY_PAID = 1506, - - /** - * The amount the exchange was asked to refund exceeds - * (with fees) the total amount of the deposit (including fees). - * This response is provided with HTTP status code - * MHD_HTTP_PRECONDITION_FAILED. - */ - TALER_EC_REFUND_INSUFFICIENT_FUNDS = 1507, - - /** - * The exchange failed to recover information about the - * denomination key of the refunded coin (even though it - * recognizes the key). Hence it could not check the fee - * strucutre. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_REFUND_DENOMINATION_KEY_NOT_FOUND = 1508, - - /** - * The refund fee specified for the request is lower than - * the refund fee charged by the exchange for the given - * denomination key of the refunded coin. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFUND_FEE_TOO_LOW = 1509, - - /** - * The exchange failed to store the refund information to - * its database. - * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_REFUND_STORE_DB_ERROR = 1510, - - /** - * The refund fee is specified in a different currency - * than the refund amount. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH = 1511, - - /** - * The refunded amount is smaller than the refund fee, - * which would result in a negative refund. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFUND_FEE_ABOVE_AMOUNT = 1512, - - /** - * The signature of the merchant is invalid. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_REFUND_MERCHANT_SIGNATURE_INVALID = 1513, - - - /** - * The wire format specified in the "sender_account_details" - * is not understood or not supported by this exchange. - * Returned with an HTTP status code of MHD_HTTP_NOT_FOUND. - * (As we did not find an interpretation of the wire format.) - */ - TALER_EC_ADMIN_ADD_INCOMING_WIREFORMAT_UNSUPPORTED = 1600, - - /** - * The currency specified in the "amount" parameter is not - * supported by this exhange. Returned with an HTTP status - * code of MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_ADMIN_ADD_INCOMING_CURRENCY_UNSUPPORTED = 1601, - - /** - * The exchange failed to store information about the incoming - * transfer in its database. This response is provided with HTTP - * status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_ADMIN_ADD_INCOMING_DB_STORE = 1602, - - /** - * The exchange encountered an error (that is not about not finding - * the wire transfer) trying to lookup a wire transfer identifier - * in the database. This response is provided with HTTP - * status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSFER_DB_FETCH_FAILED = 1700, - - /** - * The exchange found internally inconsistent data when resolving a - * wire transfer identifier in the database. This response is - * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSFER_DB_INCONSISTENT = 1701, - - /** - * The exchange did not find information about the specified - * wire transfer identifier in the database. This response is - * provided with HTTP status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND = 1702, - - - /** - * The exchange found internally inconsistent fee data when - * resolving a transaction in the database. This - * response is provided with HTTP status code - * MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSACTION_DB_FEE_INCONSISTENT = 1800, - - /** - * The exchange encountered an error (that is not about not finding - * the transaction) trying to lookup a transaction - * in the database. This response is provided with HTTP - * status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSACTION_DB_FETCH_FAILED = 1801, - - /** - * The exchange did not find information about the specified - * transaction in the database. This response is - * provided with HTTP status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_TRACK_TRANSACTION_NOT_FOUND = 1802, - - /** - * The exchange failed to identify the wire transfer of the - * transaction (or information about the plan that it was supposed - * to still happen in the future). This response is provided with - * HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSACTION_WTID_RESOLUTION_ERROR = 1803, - - /** - * The signature of the merchant is invalid. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_TRACK_TRANSACTION_MERCHANT_SIGNATURE_INVALID = 1804, - - - /* *********** Merchant backend error codes ********* */ - - /** - * The backend could not find the merchant instance specified - * in the request. This response is - * provided with HTTP status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_CONTRACT_INSTANCE_UNKNOWN = 2000, - - /** - * The exchange failed to provide a meaningful response - * to a /deposit request. This response is provided - * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE. - */ - TALER_EC_PAY_EXCHANGE_FAILED = 2101, - - /** - * The merchant failed to commit the exchanges' response to - * a /deposit request to its database. This response is provided - * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_PAY_DB_STORE_PAY_ERROR = 2102, - - /** - * The specified exchange is not supported/trusted by - * this merchant. This response is provided - * with HTTP status code MHD_HTTP_PRECONDITION_FAILED. - */ - TALER_EC_PAY_EXCHANGE_REJECTED = 2103, - - /** - * The denomination key used for payment is not listed among the - * denomination keys of the exchange. This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PAY_DENOMINATION_KEY_NOT_FOUND = 2104, - - /** - * The denomination key used for payment is not audited by an - * auditor approved by the merchant. This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PAY_DENOMINATION_KEY_AUDITOR_FAILURE = 2105, - - /** - * There was an integer overflow totaling up the amounts or - * deposit fees in the payment. This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PAY_AMOUNT_OVERFLOW = 2106, - - /** - * The deposit fees exceed the total value of the payment. - * This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PAY_FEES_EXCEED_PAYMENT = 2107, - - /** - * After considering deposit fees, the payment is insufficient - * to satisfy the required amount for the contract. - * This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PAY_PAYMENT_INSUFFICIENT_DUE_TO_FEES = 2108, - - /** - * While the merchant is happy to cover all applicable deposit fees, - * the payment is insufficient to satisfy the required amount for - * the contract. This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PAY_PAYMENT_INSUFFICIENT = 2109, - - /** - * The signature over the contract of one of the coins - * was invalid. This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PAY_COIN_SIGNATURE_INVALID = 2110, - - /** - * We failed to contact the exchange for the /pay request. - * This response is provided - * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE. - */ - TALER_EC_PAY_EXCHANGE_TIMEOUT = 2111, - - /** - * The backend could not find the merchant instance specified - * in the request. This response is - * provided with HTTP status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_PAY_INSTANCE_UNKNOWN = 2112, - - /** - * The signature over the contract of the merchant - * was invalid. This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PAY_MERCHANT_SIGNATURE_INVALID = 2113, - - /** - * The refund deadline was after the transfer deadline. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE = 2114, - - /** - * The request fails to provide coins for the payment. - * This response is provided with HTTP status code - * MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PAY_COINS_ARRAY_EMPTY = 2115, - - /** - * The merchant failed to fetch the merchant's previous state with - * respect to a /pay request from its database. This response is - * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_PAY_DB_FETCH_PAY_ERROR = 2116, - - /** - * The merchant failed to fetch the merchant's previous state with - * respect to transactions from its database. This response is - * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR = 2117, - - /** - * The transaction ID was used for a conflicing transaction before. - * This response is - * provided with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PAY_DB_TRANSACTION_ID_CONFLICT = 2118, - - /** - * The merchant failed to store the merchant's state with - * respect to the transaction in its database. This response is - * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR = 2119, - - /** - * The exchange failed to provide a valid response to - * the merchant's /keys request. - * This response is provided - * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE. - */ - TALER_EC_PAY_EXCHANGE_KEYS_FAILURE = 2120, - - /** - * The payment is too late, the offer has expired. - * This response is - * provided with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_PAY_OFFER_EXPIRED = 2121, - - - /** - * Integer overflow with sepcified timestamp argument detected. - * This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_HISTORY_TIMESTAMP_OVERFLOW = 2200, - - /** - * Failed to retrieve history from merchant database. - * This response is provided - * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_HISTORY_DB_FETCH_ERROR = 2201, - - /** - * We failed to contact the exchange for the /track/transaction - * request. This response is provided with HTTP status code - * MHD_HTTP_SERVICE_UNAVAILABLE. - */ - TALER_EC_TRACK_TRANSACTION_EXCHANGE_TIMEOUT = 2300, - - /** - * The backend could not find the merchant instance specified - * in the request. This response is - * provided with HTTP status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_TRACK_TRANSACTION_INSTANCE_UNKNOWN = 2301, - - /** - * The backend could not find the transaction specified - * in the request. This response is - * provided with HTTP status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_TRACK_TRANSACTION_TRANSACTION_UNKNOWN = 2302, - - /** - * The backend had a database access error trying to - * retrieve transaction data from its database. - * The response is - * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSACTION_DB_FETCH_TRANSACTION_ERROR = 2303, - - /** - * The backend had a database access error trying to - * retrieve payment data from its database. - * The response is - * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSACTION_DB_FETCH_PAYMENT_ERROR = 2304, - - /** - * The backend found no applicable deposits in the database. - * This is odd, as we know about the transaction, but not - * about deposits we made for the transaction. The response is - * provided with HTTP status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_TRACK_TRANSACTION_DB_NO_DEPOSITS_ERROR = 2305, - - /** - * We failed to obtain a wire transfer identifier for one - * of the coins in the transaction. The response is - * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY if - * the exchange had a hard error, or MHD_HTTP_ACCEPTED if the - * exchange signaled that the transfer was in progress. - */ - TALER_EC_TRACK_TRANSACTION_COIN_TRACE_ERROR = 2306, - - /** - * We failed to obtain the full wire transfer identifier for the - * transfer one of the coins was aggregated into. - * The response is - * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY. - */ - TALER_EC_TRACK_TRANSACTION_WIRE_TRANSFER_TRACE_ERROR = 2307, - - /** - * We got conflicting reports from the exhange with - * respect to which transfers are included in which - * aggregate. - * The response is - * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY. - */ - TALER_EC_TRACK_TRANSACTION_CONFLICTING_REPORTS = 2308, - - - /** - * We failed to contact the exchange for the /track/transfer - * request. This response is provided with HTTP status code - * MHD_HTTP_SERVICE_UNAVAILABLE. - */ - TALER_EC_TRACK_TRANSFER_EXCHANGE_TIMEOUT = 2400, - - /** - * The backend could not find the merchant instance specified - * in the request. This response is - * provided with HTTP status code MHD_HTTP_NOT_FOUND. - */ - TALER_EC_TRACK_TRANSFER_INSTANCE_UNKNOWN = 2401, - - /** - * We failed to persist coin wire transfer information in - * our merchant database. - * The response is - * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSFER_DB_STORE_COIN_ERROR = 2402, - - /** - * We internally failed to execute the /track/transfer request. - * The response is - * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSFER_REQUEST_ERROR = 2403, - - /** - * We failed to persist wire transfer information in - * our merchant database. - * The response is - * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSFER_DB_STORE_TRANSFER_ERROR = 2404, - - /** - * The exchange returned an error from /track/transfer. - * The response is - * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY. - */ - TALER_EC_TRACK_TRANSFER_EXCHANGE_ERROR = 2405, - - /** - * We failed to fetch deposit information from - * our merchant database. - * The response is - * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSFER_DB_FETCH_DEPOSIT_ERROR = 2406, - - /** - * We encountered an internal logic error. - * The response is - * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSFER_DB_INTERNAL_LOGIC_ERROR = 2407, - - /** - * The exchange gave conflicting information about a coin which has - * been wire transferred. - * The response is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TRACK_TRANSFER_CONFLICTING_REPORTS = 2408, - - /** - * The hash provided in the request of /map/in does not match - * the contract sent alongside in the same request. - */ - TALER_EC_MAP_IN_UNMATCHED_HASH = 2500, - - /** - * The backend encountered an error while trying to store the - * pair into the database. - * The response is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_MAP_IN_STORE_DB_ERROR = 2501, - - /** - * The backend encountered an error while trying to retrieve the - * contract from database. Likely to be an internal error. - */ - TALER_EC_MAP_OUT_GET_FROM_DB_ERROR = 2502, - - - /** - * The backend encountered an error while trying to retrieve the - * contract from database. Likely to be an internal error. - */ - TALER_EC_MAP_OUT_CONTRACT_UNKNOWN = 2503, - - /* ********** /test API error codes ************* */ - - /** - * The exchange failed to compute ECDH. This response is provided - * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TEST_ECDH_ERROR = 4000, - - /** - * The EdDSA test signature is invalid. This response is provided - * with HTTP status code MHD_HTTP_BAD_REQUEST. - */ - TALER_EC_TEST_EDDSA_INVALID = 4001, - - /** - * The exchange failed to compute the EdDSA test signature. This response is provided - * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TEST_EDDSA_ERROR = 4002, - - /** - * The exchange failed to generate an RSA key. This response is provided - * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TEST_RSA_GEN_ERROR = 4003, - - /** - * The exchange failed to compute the public RSA key. This response - * is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TEST_RSA_PUB_ERROR = 4004, - - /** - * The exchange failed to compute the RSA signature. This response - * is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. - */ - TALER_EC_TEST_RSA_SIGN_ERROR = 4005, - - - /** - * End of error code range. - */ - TALER_EC_END = 9999 - }; diff --git a/api-exchange.rst b/api-exchange.rst deleted file mode 100644 index 1d03dae9..00000000 --- a/api-exchange.rst +++ /dev/null @@ -1,1546 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014-2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING. If not, see - - @author Christian Grothoff - -============================= -The Exchange RESTful JSON API -============================= - -The API specified here follows the :ref:`general conventions ` -for all details not specified in the individual requests. -The `glossary ` -defines all specific terms used in this section. - -.. _keys: - ------------------------ -Obtaining Exchange Keys ------------------------ - -This API is used by wallets and merchants to obtain global information about -the exchange, such as online signing keys, available denominations and the fee -structure. This is typically the first call any exchange client makes, as it -returns information required to process all of the other interactions with the -exchange. The returned information is secured by (1) signature(s) from the exchange, -especially the long-term offline signing key of the exchange, which clients should -cache; (2) signature(s) from auditors, and the auditor keys should be -hard-coded into the wallet as they are the trust anchors for Taler; (3) -possibly by using HTTPS. - - -.. http:get:: /keys - - Get a list of all denomination keys offered by the bank, - as well as the bank's current online signing key. - - **Request:** - - :query last_issue_date: optional argument specifying the maximum value of any of the "stamp_start" members of the denomination keys of a "/keys" response that is already known to the client. Allows the exchange to only return keys that have changed since that timestamp. The given value must be an unsigned 64-bit integer representing seconds after 1970. If the timestamp does not exactly match the "stamp_start" of one of the denomination keys, all keys are returned. - - **Response:** - - :status 200 OK: - The exchange responds with a `ExchangeKeysResponse`_ object. This request should - virtually always be successful. - - **Details:** - - .. _ExchangeKeysResponse: - .. code-block:: tsref - - interface ExchangeKeysResponse { - // libtool-style representation of the Taler protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // The format is "current:revision:age". - version: String; - - // EdDSA master public key of the exchange, used to sign entries in `denoms` and `signkeys` - master_public_key: EddsaPublicKey; - - // Relative duration until inactive reserves are closed; not signed, expressed as - // a string in relative time in microseconds, i.e. "/Delay(1000)/" for 1 second. - reserve_closing_delay: RelativeTime; - - // Denominations offered by this exchange. - denoms: Denom[]; - - // Denominations for which the exchange currently offers/requests payback. - payback: Payback[]; - - // The date when the denomination keys were last updated. - list_issue_date: Timestamp; - - // Auditors of the exchange. - auditors: Auditor[]; - - // The exchange's signing keys. - signkeys: SignKey[]; - - // compact EdDSA `signature`_ (binary-only) over the SHA-512 hash of the - // concatenation of all SHA-512 hashes of the RSA denomination public keys - // in `denoms` in the same order as they were in `denoms`. Note that for - // hashing, the binary format of the RSA public keys is used, and not their - // `base32 encoding `_. Wallets cannot do much with this signature by itself; - // it is only useful when multiple clients need to establish that the exchange - // is sabotaging end-user anonymity by giving disjoint denomination keys to - // different users. If a exchange were to do this, this signature allows the - // clients to demonstrate to the public that the exchange is dishonest. - eddsa_sig: EddsaSignature; - - // Public EdDSA key of the exchange that was used to generate the signature. - // Should match one of the exchange's signing keys from /keys. It is given - // explicitly as the client might otherwise be confused by clock skew as to - // which signing key was used. - eddsa_pub: EddsaPublicKey; - } - - .. _tsref-type-Denom: - .. code-block:: tsref - - interface Denom { - // How much are coins of this denomination worth? - value: Amount; - - // When does the denomination key become valid? - stamp_start: Timestamp; - - // When is it no longer possible to deposit coins - // of this denomination? - stamp_expire_withdraw: Timestamp; - - // Timestamp indicating by when legal disputes relating to these coins must - // be settled, as the exchange will afterwards destroy its evidence relating to - // transactions involving this coin. - stamp_expire_legal: Timestamp; - - // Public (RSA) key for the denomination. - denom_pub: RsaPublicKey; - - // Fee charged by the exchange for withdrawing a coin of this denomination - fee_withdraw: Amount; - - // Fee charged by the exchange for depositing a coin of this denomination - fee_deposit: Amount; - - // Fee charged by the exchange for refreshing a coin of this denomination - fee_refresh: Amount; - - // Fee charged by the exchange for refunding a coin of this denomination - fee_refund: Amount; - - // Signature of `TALER_DenominationKeyValidityPS`_ - master_sig: EddsaSignature; - } - - Fees for any of the operations can be zero, but the fields must still be - present. The currency of the `fee_deposit`, `fee_refresh` and `fee_refund` must match the - currency of the `value`. Theoretically, the `fee_withdraw` could be in a - different currency, but this is not currently supported by the - implementation. - - .. _tsref-type-Payback: - .. code-block:: tsref - - interface Payback { - // hash of the public key of the denomination that is being revoked under - // emergency protocol (see /payback). - h_denom_pub: HashCode; - - // We do not include any signature here, as the primary use-case for - // this emergency involves the exchange having lost its signing keys, - // so such a signature here would be pretty worthless. However, the - // exchange will not honor /payback requests unless they are for - // denomination keys listed here. - } - - A signing key in the `signkeys` list is a JSON object with the following fields: - - .. _tsref-type-SignKey: - .. code-block:: tsref - - interface SignKey { - // The actual exchange's EdDSA signing public key. - key: EddsaPublicKey; - - // Initial validity date for the signing key. - stamp_start: Timestamp; - - // Date when the exchange will stop using the signing key, allowed to overlap - // slightly with the next signing key's validity to allow for clock skew. - stamp_expire: Timestamp; - - // Date when all signatures made by the signing key expire and should - // henceforth no longer be considered valid in legal disputes. - stamp_end: Timestamp; - - // Signature over `key` and `stamp_expire` by the exchange master key. - // Must have purpose TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY. - master_sig: EddsaSignature; - } - - An entry in the `auditors` list is a JSON object with the following fields: - - .. _tsref-type-Auditor: - .. code-block:: tsref - - interface Auditor { - // The auditor's EdDSA signing public key. - auditor_pub: EddsaPublicKey; - - // The auditor's URL. - auditor_url: string; - - // An array of denomination keys the auditor affirms with its signature. - // Note that the message only includes the hash of the public key, while the - // signature is actually over the expanded information including expiration - // times and fees. The exact format is described below. - denomination_keys: DenominationKey[]; - } - - .. _tsref-type-DenominationKey: - .. code-block:: tsref - - interface DenominationKey { - // hash of the public RSA key used to sign coins of the respective - // denomination. Note that the auditor's signature covers more than just - // the hash, but this other information is already provided in `denoms` and - // thus not repeated here. - denom_pub_h: HashCode; - - // Signature of `TALER_ExchangeKeyValidityPS`_ - auditor_sig: EddsaSignature; - } - - The same auditor may appear multiple times in the array for different subsets - of denomination keys, and the same denomination key hash may be listed - multiple times for the same or different auditors. The wallet or merchant - just should check that the denomination keys they use are in the set for at - least one of the auditors that they accept. - - .. note:: - - Both the individual denominations *and* the denomination list is signed, - allowing customers to prove that they received an inconsistent list. - -.. _wire-req: - ------------------------------------ -Obtaining wire-transfer information ------------------------------------ - -.. http:get:: /wire - - Returns a list of payment methods supported by the exchange. The idea is that wallets may use this information to instruct users on how to perform wire transfers to top up their wallets. - - **Response:** - - :status 200: The exchange responds with a `WireResponse`_ object. This request should virtually always be successful. - - **Details:** - - .. _WireResponse: - .. _tsref-type-WireResponse: - .. code-block:: tsref - - interface WireResponse { - - // Array of wire accounts operated by the exchange for - // incoming wire transfers. - accounts: WireAccount[]; - - // Object mapping names of wire methods (i.e. "sepa" or "x-taler-bank") - // to wire fees. - fees: { method : AggregateTransferFee }; - } - - The specification for the account object is: - - .. _WireAccouunt: - .. _tsref-type-WireAccount: - .. code-block:: tsref - - interface WireAccount { - // payto:// URL identifying the account and wire method - url: string; - - // Salt value (used when hashing 'url' to verify signature) - salt: string; - - // Signature using the exchange's offline key - // with purpose TALER_SIGNATURE_MASTER_WIRE_DETAILS. - master_sig: EddsaSignature; - } - - Aggregate wire transfer fees representing the fees the exchange - charges per wire transfer to a merchant must be specified as an - array in all wire transfer response objects under `fees`. The - respective array contains objects with the following members: - - .. _AggregateTransferFee: - .. _tsref-type-AggregateTransferFee: - .. code-block:: tsref - - interface AggregateTransferFee { - // Per transfer wire transfer fee. - wire_fee: Amount; - - // Per transfer closing fee. - closing_fee: Amount; - - // What date (inclusive) does this fee go into effect? - // The different fees must cover the full time period in which - // any of the denomination keys are valid without overlap. - start_date: Timestamp; - - // What date (exclusive) does this fee stop going into effect? - // The different fees must cover the full time period in which - // any of the denomination keys are valid without overlap. - end_date: Timestamp; - - // Signature of `TALER_MasterWireFeePS`_ with purpose TALER_SIGNATURE_MASTER_WIRE_FEES - sig: EddsaSignature; - } - ----------- -Withdrawal ----------- - -This API is used by the wallet to obtain digital coins. - -When transfering money to the exchange such as via SEPA transfers, the exchange creates -a *reserve*, which keeps the money from the customer. The customer must -specify an EdDSA reserve public key as part of the transfer, and can then -withdraw digital coins using the corresponding private key. All incoming and -outgoing transactions are recorded under the corresponding public key by the -exchange. - - .. note:: - - Eventually the exchange will need to advertise a policy for how long it will keep transaction histories for inactive or even fully drained reserves. We will therefore need some additional handler similar to `/keys` to advertise those terms of service. - - -.. http:get:: /reserve/status - - Request information about a reserve. - - .. note:: - The client currently does not have to demonstrate knowledge of the private - key of the reserve to make this request, which makes the reserve's public - key privileged information known only to the client, their bank, and the - exchange. In future, we might wish to revisit this decision to improve - security, such as by having the client EdDSA-sign an ECDHE key to be used - to derive a symmetric key to encrypt the response. This would be useful if - for example HTTPS were not used for communication with the exchange. - - **Request:** - - :query reserve_pub: EdDSA reserve public key identifying the reserve. - - **Response:** - - :status 200 OK: - The exchange responds with a `ReserveStatus`_ object; the reserve was known to the exchange, - :status 404 Not Found: The reserve key does not belong to a reserve known to the exchange. - - **Details:** - - .. _ReserveStatus: - .. code-block:: tsref - - interface ReserveStatus { - // Balance left in the reserve. - balance: Amount; - - // Transaction history for this reserve - history: TransactionHistoryItem[]; - } - - Objects in the transaction history have the following format: - - .. _tsref-type-TransactionHistoryItem: - .. code-block:: tsref - - interface TransactionHistoryItem { - // Either "WITHDRAW", "DEPOSIT", "PAYBACK", or "CLOSING" - type: string; - - // The amount that was withdrawn or deposited (incl. fee) - // or paid back, or the closing amount. - amount: Amount; - - // Hash of the denomination public key of the coin, if - // type is "WITHDRAW". - h_denom_pub?: base32; - - // Hash of the blinded coin to be signed, if - // type is "WITHDRAW". - h_coin_envelope?: base32; - - // Signature of `TALER_WithdrawRequestPS`_ created with the `reserves's private key `_. Only present if type is "WITHDRAW". - reserve_sig?: EddsaSignature; - - // The fee that was charged for "WITHDRAW". - withdraw_fee?: Amount; - - // The fee that was charged for "CLOSING". - closing_fee?: Amount; - - // Sender account payto://-URL, only present if type is "DEPOSIT". - sender_account_url?: String; - - // Receiver account details, only present if type is "PAYBACK". - receiver_account_details?: any; - - // Wire transfer identifier, only present if type is "PAYBACK". - wire_transfer?: any; - - // Transfer details uniquely identifying the transfer, only present if type is "DEPOSIT". - wire_reference?: any; - - // Wire transfer subject, only present if type is "CLOSING". - wtid?: any; - - // Hash of the wire account into which the funds were - // returned to, present if type is "CLOSING". - h_wire?: base32; - - // If `type` is "PAYBACK", this is a signature over a `struct TALER_PaybackConfirmationPS` with purpose TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK. - // If `type` is "CLOSING", this is a signature over a `struct TALER_ReserveCloseConfirmationPS` with purpose TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED. - // Not present for other values of `type`. - exchange_sig?: EddsaSignature; - - // Public key used to create `exchange_sig`, only present if `exchange_sig` is present. - exchange_pub?: EddsaPublicKey; - - // Public key of the coin that was paid back; only present if type is "PAYBACK". - coin_pub?: CoinPublicKey; - - // Timestamp when the exchange received the /payback or executed the wire transfer. Only present if `type` is "DEPOSIT", "PAYBACK" or "CLOSING". - timestamp?: Timestamp; - } - - -.. http:post:: /reserve/withdraw - - Withdraw a coin of the specified denomination. Note that the client should - commit all of the request details, including the private key of the coin and - the blinding factor, to disk *before* issuing this request, so that it can - recover the information if necessary in case of transient failures, like - power outage, network outage, etc. - - **Request:** The request body must be a `WithdrawRequest`_ object. - - **Response:** - - :status 200 OK: - The request was succesful, and the response is a `WithdrawResponse`. Note that repeating exactly the same request - will again yield the same response, so if the network goes down during the - transaction or before the client can commit the coin signature to disk, the - coin is not lost. - :status 401 Unauthorized: The signature is invalid. - :status 404 Not Found: - The denomination key or the reserve are not known to the exchange. If the - denomination key is unknown, this suggests a bug in the wallet as the - wallet should have used current denomination keys from `/keys`. If the - reserve is unknown, the wallet should not report a hard error yet, but - instead simply wait for up to a day, as the wire transaction might simply - not yet have completed and might be known to the exchange in the near future. - In this case, the wallet should repeat the exact same request later again - using exactly the same blinded coin. - :status 403 Forbidden: - The balance of the reserve is not sufficient to withdraw a coin of the indicated denomination. - The response is `WithdrawError`_ object. - - - **Details:** - - .. _WithdrawRequest: - .. code-block:: tsref - - interface WithdrawRequest { - // Hash of a denomination public key (RSA), specifying the type of coin the client - // would like the exchange to create. - denom_pub_hash: HashCode; - - // coin's blinded public key, should be (blindly) signed by the exchange's - // denomination private key - coin_ev: CoinEnvelope; - - // `public (EdDSA) key `_ of the reserve from which the coin should be - // withdrawn. The total amount deducted will be the coin's value plus the - // withdrawal fee as specified with the denomination information. - reserve_pub: EddsaPublicKey; - - // Signature of `TALER_WithdrawRequestPS`_ created with the `reserves's private key `_ - reserve_sig: EddsaSignature; - } - - - .. _WithdrawResponse: - .. code-block:: tsref - - interface WithdrawResponse { - // The blinded RSA signature over the `coin_ev`, affirms the coin's - // validity after unblinding. - ev_sig: BlindedRsaSignature; - } - - .. _WithdrawError: - .. code-block:: tsref - - interface WithdrawError { - // Constant "Insufficient funds" - error: string; - - // Amount left in the reserve - balance: Amount; - - // History of the reserve's activity, in the same format as returned by /reserve/status. - history: TransactionHistoryItem[] - } - -.. _deposit-par: - -------- -Deposit -------- - -Deposit operations are requested by a merchant during a transaction. For the -deposit operation, the merchant has to obtain the deposit permission for a coin -from their customer who owns the coin. When depositing a coin, the merchant is -credited an amount specified in the deposit permission, possibly a fraction of -the total coin's value, minus the deposit fee as specified by the coin's -denomination. - - -.. _deposit: - -.. http:POST:: /deposit - - Deposit the given coin and ask the exchange to transfer the given :ref:`amount` - to the merchants bank account. This API is used by the merchant to redeem - the digital coins. The request should contain a JSON object with the - following fields: - - **Request:** The request body must be a `DepositRequest`_ object. - - **Response:** - - :status 200 Ok: - The operation succeeded, the exchange confirms that no double-spending took place. The response will include a `DepositSuccess`_ object. - :status 401 Unauthorized: - One of the signatures is invalid. - :status 403 Forbidden: - The deposit operation has failed because the coin has insufficient - residual value; the request should not be repeated again with this coin. - In this case, the response is a `DepositDoubleSpendError`_. - :status 404 Not Found: - Either the denomination key is not recognized (expired or invalid) or - the wire type is not recognized. - - **Details:** - - .. _DepositRequest: - .. code-block:: tsref - - interface DepositRequest { - // Amount to be deposited, can be a fraction of the - // coin's total value. - f: Amount; - - // The merchant's account details. This must be a JSON object whose format - // must correspond to one of the supported wire transfer formats of the exchange. - // See `wireformats`_. - wire: Object; - - // SHA-512 hash of the merchant's payment details from `wire`. Although - // strictly speaking redundant, this helps detect inconsistencies. - // TODO: change to 'h_wire'. - H_wire: HashCode; - - // SHA-512 hash of the contact of the merchant with the customer. Further - // details are never disclosed to the exchange. - h_contract_terms: HashCode; - - // `coin's public key `_, both ECDHE and EdDSA. - coin_pub: CoinPublicKey; - - // Hash of denomination RSA key with which the coin is signed - denom_pub_hash: HashCode; - - // exchange's unblinded RSA signature of the coin - ub_sig: RsaSignature; - - // timestamp when the contract was finalized, must match approximately the - // current time of the exchange; if the timestamp is too far off, the - // exchange returns "400 Bad Request" with an error code of - // "TALER_EC_DEPOSIT_INVALID_TIMESTAMP". - timestamp: Timestamp; - - // indicative time by which the exchange undertakes to transfer the funds to - // the merchant, in case of successful payment. - wire_deadline: Timestamp; - - // EdDSA `public key of the merchant `_, so that the client can identify the - // merchant for refund requests. - merchant_pub: EddsaPublicKey; - - // date until which the merchant can issue a refund to the customer via the - // exchange, possibly zero if refunds are not allowed. - refund_deadline: Timestamp; - - // Signature of `TALER_DepositRequestPS`_, made by the customer with the `coin's private key `_ - coin_sig: EddsaSignature; - } - - The deposit operation succeeds if the coin is valid for making a deposit and - has enough residual value that has not already been deposited or melted. - - - .. _`tsref-type-DepositSuccess`: - .. _DepositSuccess: - .. code-block:: tsref - - interface DepositSuccess { - // The string constant "DEPOSIT_OK" - status: string; - - // the EdDSA signature of `TALER_DepositConfirmationPS`_ using a current - // `signing key of the exchange `_ affirming the successful - // deposit and that the exchange will transfer the funds after the refund - // deadline, or as soon as possible if the refund deadline is zero. - sig: EddsaSignature; - - // `public EdDSA key of the exchange `_ that was used to - // generate the signature. - // Should match one of the exchange's signing keys from /keys. It is given - // explicitly as the client might otherwise be confused by clock skew as to - // which signing key was used. - pub: EddsaPublicKey; - } - - .. _DepositDoubleSpendError: - .. code-block:: tsref - - interface DepositDoubleSpendError { - // The string constant "insufficient funds" - error: string; - - // Transaction history for the coin that is - // being double-spended - history: CoinSpendHistoryItem[]; - } - - .. _`tsref-type-CoinSpendHistoryItem`: - .. _CoinSpendHistoryItem: - .. code-block:: tsref - - interface CoinSpendHistoryItem { - // Either "DEPOSIT", "MELT", "REFUND", "PAYBACK", - // "OLD-COIN-PAYBACK" or "PAYBACK-REFRESH" - type: string; - - // The total amount of the coin's value absorbed (or restored in the case of a refund) by this transaction. - // Note that for deposit and melt this means the amount given includes - // the transaction fee, while for refunds the amount given excludes - // the transaction fee. The current coin value can thus be computed by - // subtracting deposit and melt amounts and adding refund amounts from - // the coin's denomination value. - amount: Amount; - - // Deposit fee in case of type "DEPOSIT". - deposit_fee: Amount; - - // public key of the merchant, for "DEPOSIT" operations. - merchant_pub?: EddsaPublicKey; - - // date when the operation was made. - // Only for "DEPOSIT", "PAYBACK", "OLD-COIN-PAYBACK" and - // "PAYBACK-REFRESH" operations. - timestamp?: Timestamp; - - // date until which the merchant can issue a refund to the customer via the - // exchange, possibly zero if refunds are not allowed. Only for "DEPOSIT" operations. - refund_deadline?: Timestamp; - - // Signature by the coin, only present if `type` is "DEPOSIT" or "MELT" - coin_sig?: EddsaSignature; - - // Deposit fee in case of type "MELT". - melt_fee: Amount; - - // Commitment from the melt operation, only for "MELT". - rc?: TALER_RefreshCommitmentP; - - // Hash of the bank account from where we received the funds, - // only present if `type` is "DEPOSIT" - h_wire?: HashCode; - - // Deposit fee in case of type "REFUND". - refund_fee?: Amount; - - // Hash over the proposal data of the contract that - // is being paid (if type is "DEPOSIT") or refunded (if - // `type` is "REFUND"); otherwise absent. - h_contract_terms?: HashCode; - - // Refund transaction ID. Only present if `type` is - // "REFUND" - rtransaction_id?: integer; - - // `EdDSA Signature `_ authorizing the REFUND. Made with - // the `public key of the merchant `_. - // Only present if `type` is "REFUND" - merchant_sig?: EddsaSignature; - - // public key of the reserve that will receive the funds, for "PAYBACK" operations. - reserve_pub?: EddsaPublicKey; - - // Signature by the exchange, only present if `type` is "PAYBACK", - // "OLD-COIN-PAYBACK" or "PAYBACK-REFRESH". Signature is - // of type TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK for "PAYBACK", - // and of type TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK_REFRESH otherwise. - exchange_sig?: EddsaSignature; - - // public key used to sign `exchange_sig`, only present if `exchange_sig` present. - exchange_pub?: EddsaPublicKey; - - // Blinding factor of the revoked new coin, - // only present if `type` is "REFRESH_PAYBACK". - new_coin_blinding_secret: RsaBlindingKeySecret; - - // Blinded public key of the revoked new coin, - // only present if `type` is "REFRESH_PAYBACK". - new_coin_ev: RsaBlindingKeySecret; - } - ----------- -Refreshing ----------- - -Refreshing creates `n` new coins from `m` old coins, where the sum of -denominations of the new coins must be smaller than the sum of the old coins' -denominations plus melting (refresh) and withdrawal fees charged by the exchange. -The refreshing API can be used by wallets to melt partially spent coins, making -transactions with the freshly exchangeed coins unlinkabe to previous transactions -by anyone except the wallet itself. - -However, the new coins are linkable from the private keys of all old coins -using the /refresh/link request. While /refresh/link must be implemented by -the exchange to achieve taxability, wallets do not really ever need that part of -the API during normal operation. - -.. _refresh: -.. http:post:: /refresh/melt - - "Melts" coins. Invalidates the coins and prepares for exchangeing of fresh - coins. Taler uses a global parameter `kappa` for the cut-and-choose - component of the protocol, for which this request is the commitment. Thus, - various arguments are given `kappa`-times in this step. At present `kappa` - is always 3. - - - :status 401 Unauthorized: - One of the signatures is invalid. - :status 200 OK: - The request was succesful. The response body is `MeltResponse`_ in this case. - :status 403 Forbidden: - The operation is not allowed as at least one of the coins has insufficient funds. The response - is `MeltForbiddenResponse`_ in this case. - :status 404: - the exchange does not recognize the denomination key as belonging to the exchange, - or it has expired - - **Details:** - - - .. code-block:: tsref - - interface MeltRequest { - - // `Coin public key `_, uniquely identifies the coin to be melted - coin_pub: string; - - // Hash of the denomination public key, to determine total coin value. - denom_pub_hash: HashCode; - - // Signature over the `coin public key `_ by the denomination. - denom_sig: RsaSignature; - - // Signature by the `coin `_ over the melt commitment. - confirm_sig: EddsaSignature; - - // Amount of the value of the coin that should be melted as part of - // this refresh operation, including melting fee. - value_with_fee: Amount; - - // Melt commitment. Hash over the various coins to be withdrawn. - // See also `TALER_refresh_get_commitment()` - rc: TALER_RefreshCommitmentP; - - } - - For details about the HKDF used to derive the new coin private keys and - the blinding factors from ECDHE between the transfer public keys and - the private key of the melted coin, please refer to the - implementation in `libtalerutil`. - - .. _tsref-type-MeltResponse: - .. _MeltResponse: - .. code-block:: tsref - - interface MeltResponse { - // Which of the `kappa` indices does the client not have to reveal. - noreveal_index: number; - - // Signature of `TALER_RefreshMeltConfirmationPS`_ whereby the exchange - // affirms the successful melt and confirming the `noreveal_index` - exchange_sig: EddsaSignature; - - // `public EdDSA key `_ of the exchange that was used to generate the signature. - // Should match one of the exchange's signing keys from /keys. Again given - // explicitly as the client might otherwise be confused by clock skew as to - // which signing key was used. - exchange_pub: EddsaPublicKey; - } - - - .. _tsref-type-MeltForbiddenResponse: - .. _MeltForbiddenResponse: - .. code-block:: tsref - - interface MeltForbiddenResponse { - // Always "insufficient funds" - error: string; - - // public key of a melted coin that had insufficient funds - coin_pub: EddsaPublicKey; - - // original total value of the coin - original_value: Amount; - - // remaining value of the coin - residual_value: Amount; - - // amount of the coin's value that was to be melted - requested_value: Amount; - - // The transaction list of the respective coin that failed to have sufficient funds left. - // Note that only the transaction history for one bogus coin is given, - // even if multiple coins would have failed the check. - history: CoinSpendHistoryItem[]; - } - - -.. http:post:: /refresh/reveal - - Reveal previously commited values to the exchange, except for the values - corresponding to the `noreveal_index` returned by the /exchange/melt step. - - Errors such as failing to do proper arithmetic when it comes to calculating - the total of the coin values and fees are simply reported as bad requests. - This includes issues such as melting the same coin twice in the same session, - which is simply not allowed. However, theoretically it is possible to melt a - coin twice, as long as the `value_with_fee` of the two melting operations is - not larger than the total remaining value of the coin before the melting - operations. Nevertheless, this is not really useful. - - :status 200 OK: - The transfer private keys matched the commitment and the original request was well-formed. - The response body is a `RevealResponse`_ - :status 409 Conflict: - There is a problem between the original commitment and the revealed private - keys. The returned information is proof of the missmatch, and therefore - rather verbose, as it includes most of the original /refresh/melt request, - but of course expected to be primarily used for diagnostics. - The response body is a `RevealConflictResponse`_. - - **Details:** - - Request body contains a JSON object with the following fields: - - .. code-block:: tsref - - interface RevealRequest { - - // Array of `n` new hash codes of denomination public keys to order. - new_denoms_h: HashCode[]; - - // Array of `n` entries with blinded coins, - // matching the respective entries in `new_denoms`. - coin_evs: CoinEnvelope[]; - - // `kappa - 1` transfer private keys (ephemeral ECDHE keys) - transfer_privs: EddsaPrivateKey[]; - - // transfer public key at the `noreveal_index`. - transfer_pub: EddsaPublicKey; - - // Array of `n` signatures made by the wallet using the old coin's private key, - // used later to verify the /refresh/link response from the exchange. - // Signs over a `TALER_CoinLinkSignaturePS`_ - link_sigs: EddsaSignature[]; - - // The original commitment, used to match the /refresh/reveal - // to the corresponding /refresh/melt operation. - rc: HashCode; - } - - - .. _RevealResponse: - .. code-block:: tsref - - interface RevealResponse { - // List of the exchange's blinded RSA signatures on the new coins. Each - // element in the array is another JSON object which contains the signature - // in the "ev_sig" field. - ev_sigs: BlindedRsaSignature[]; - } - - - .. _RevealConflictResponse: - .. code-block:: tsref - - interface RevealConflictResponse { - // Constant "commitment violation" - error: string; - - // Detailed error code - code: integer; - - // Commitment as calculated by the exchange from the revealed data. - rc_expected: HashCode; - - } - - -.. http:get:: /refresh/link - - Link the old public key of a melted coin to the coin(s) that were exchangeed during the refresh operation. - - **Request:** - - :query coin_pub: melted coin's public key - - **Response:** - - :status 200 OK: - All commitments were revealed successfully. The exchange returns an array, - typically consisting of only one element, in which each each element contains - information about a melting session that the coin was used in. - :status 404 Not Found: - The exchange has no linkage data for the given public key, as the coin has not - yet been involved in a refresh operation. - - **Details:** - - .. _tsref-type-LinkResponse: - .. code-block:: tsref - - interface LinkResponse { - // transfer ECDHE public key corresponding to the `coin_pub`, used to - // compute the blinding factor and private key of the fresh coins. - transfer_pub: EcdhePublicKey; - - // array with (encrypted/blinded) information for each of the coins - // exchangeed in the refresh operation. - new_coins: NewCoinInfo[]; - } - - .. _tsref-type-NewCoinInfo: - .. code-block:: tsref - - interface NewCoinInfo { - // RSA public key of the exchangeed coin. - denom_pub: RsaPublicKey; - - // Exchange's blinded signature over the exchangeed coin. - ev_sig: BlindedRsaSignature; - - // Blinded coin, to be verified by the wallet to protect against - // a malicious exchange. - coin_ev: CoinEnvelope; - - // Signature made by the old coin over the refresh request. - // Signs over a `TALER_CoinLinkSignaturePS`_ - link_sig: EddsaSignature; - } - - -------------------- -Emergency Cash-Back -------------------- - -This API is only used if the exchange is either about to go out of -business or has had its private signing keys compromised (so in -either case, the protocol is only used in **abnormal** -situations). In the above cases, the exchange signals to the -wallets that the emergency cash back protocol has been activated -by putting the affected denomination keys into the cash-back -part of the /keys response. If and only if this has happened, -coins that were signed with those denomination keys can be cashed -in using this API. - - .. note:: - - This is a proposed API, we are implementing it as bug #3887. - -.. http:post:: /payback - - Demand that a coin be refunded via wire transfer to the original owner. - - **Request:** The request body must be a `PaybackRequest`_ object. - - **Response:** - :status 200 OK: - The request was succesful, and the response is a `PaybackConfirmation`. - Note that repeating exactly the same request - will again yield the same response, so if the network goes down during the - transaction or before the client can commit the coin signature to disk, the - coin is not lost. - :status 401 Unauthorized: The coin's signature is invalid. - :status 403 Forbidden: The coin was already used for payment. - The response is a `DepositDoubleSpendError`_. - :status 404 Not Found: - The denomination key is not in the set of denomination - keys where emergency pay back is enabled, or the blinded - coin is not known to have been withdrawn. - - **Details:** - - .. _PaybackRequest: - .. code-block:: tsref - - interface PaybackRequest { - // Hash of denomination public key (RSA), specifying the type of coin the client - // would like the exchange to pay back. - denom_pub_hash: HashCode; - - // Signature over the `coin public key `_ by the denomination. - denom_sig: RsaSignature; - - // coin's public key - coin_pub: CoinPublicKey; - - // coin's blinding factor - coin_blind_key_secret: RsaBlindingKeySecret; - - // Signature of `TALER_PaybackRequestPS`_ created with the `coin's private key `_ - coin_sig: EddsaSignature; - - // Was the coin refreshed (and thus the payback should go to the old coin)? - // Optional (for backwards compatibility); if absent, "false" is assumed - refreshed?: boolean; - } - - - .. _PaybackConfirmation: - .. code-block:: tsref - - interface PaybackConfirmation { - // public key of the reserve that will receive the payback, - // provided if refreshed was false. - reserve_pub?: EddsaPublicKey; - - // public key of the old coin that will receive the payback, - // provided if refreshed was true. - old_coin_pub?: EddsaPublicKey; - - // How much will the exchange pay back (needed by wallet in - // case coin was partially spent and wallet got restored from backup) - amount: Amount; - - // Time by which the exchange received the /payback request. - timestamp: Timestamp; - - // the EdDSA signature of `TALER_PaybackConfirmationPS`_ (refreshed false) - // or `TALER_PaybackRefreshConfirmationPS_` (refreshed true) using a current - // `signing key of the exchange `_ affirming the successful - // payback request, and that the exchange promises to transfer the funds - // by the date specified (this allows the exchange delaying the transfer - // a bit to aggregate additional payback requests into a larger one). - exchange_sig: EddsaSignature; - - // Public EdDSA key of the exchange that was used to generate the signature. - // Should match one of the exchange's signing keys from /keys. It is given - // explicitly as the client might otherwise be confused by clock skew as to - // which signing key was used. - exchange_pub: EddsaPublicKey; - } - - ------------------------ -Tracking wire transfers ------------------------ - -This API is used by merchants that need to find out which wire -transfers (from the exchange to the merchant) correspond to which deposit -operations. Typically, a merchant will receive a wire transfer with a -**wire transfer identifier** and want to know the set of deposit -operations that correspond to this wire transfer. This is the -preferred query that merchants should make for each wire transfer they -receive. If a merchant needs to investigate a specific deposit -operation (i.e. because it seems that it was not paid), then the -merchant can also request the wire transfer identifier for a deposit -operation. - -Sufficient information is returned to verify that the coin signatures -are correct. This also allows governments to use this API when doing -a tax audit on merchants. - -Naturally, the returned information may be sensitive for the merchant. -We do not require the merchant to sign the request, as the same requests -may also be performed by the government auditing a merchant. -However, wire transfer identifiers should have sufficient entropy to -ensure that obtaining a successful reply by brute-force is not practical. -Nevertheless, the merchant should protect the wire transfer identifiers -from his bank statements against unauthorized access, least his income -situation is revealed to an adversary. (This is not a major issue, as -an adversary that has access to the line-items of bank statements can -typically also view the balance.) - - -.. http:get:: /track/transfer - - Provides deposits associated with a given wire transfer. - - **Request:** - - :query wtid: raw wire transfer identifier identifying the wire transfer (a base32-encoded value) - - **Response:** - - :status 200 OK: - The wire transfer is known to the exchange, details about it follow in the body. - The body of the response is a `TrackTransferResponse`_. - :status 404 Not Found: - The wire transfer identifier is unknown to the exchange. - - .. _TrackTransferResponse: - .. _tsref-type-TrackTransferResponse: - .. code-block:: tsref - - interface TrackTransferResponse { - // Total amount transferred - total: Amount; - - // Applicable wire fee that was charged - wire_fee: Amount; - - // public key of the merchant (identical for all deposits) - merchant_pub: EddsaPublicKey; - - // hash of the wire details (identical for all deposits) - H_wire: HashCode; - - // Time of the execution of the wire transfer by the exchange - execution_time: Timestamp; - - // details about the deposits - deposits: TrackTransferDetail[]; - - // signature from the exchange made with purpose - // `TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT` - exchange_sig: EddsaSignature; - - // public EdDSA key of the exchange that was used to generate the signature. - // Should match one of the exchange's signing keys from /keys. Again given - // explicitly as the client might otherwise be confused by clock skew as to - // which signing key was used. - exchange_pub: EddsaSignature; - } - - .. _tsref-type-TrackTransferDetail: - .. code-block:: tsref - - interface TrackTransferDetail { - // SHA-512 hash of the contact of the merchant with the customer. - h_contract_terms: HashCode; - - // coin's public key, both ECDHE and EdDSA. - coin_pub: CoinPublicKey; - - // The total amount the original deposit was worth. - deposit_value: Amount; - - // applicable fees for the deposit - deposit_fee: Amount; - - } - -.. http:post:: /track/transaction - - Provide the wire transfer identifier associated with an (existing) deposit operation. - - **Request:** The request body must be a `TrackTransactionRequest`_ JSON object. - - **Response:** - - :status 200 OK: - The deposit has been executed by the exchange and we have a wire transfer identifier. - The response body is a `TrackTransactionResponse`_ object. - :status 202 Accepted: - The deposit request has been accepted for processing, but was not yet - executed. Hence the exchange does not yet have a wire transfer identifier. The - merchant should come back later and ask again. - The response body is a `TrackTransactionAcceptedResponse`_. - :status 401 Unauthorized: The signature is invalid. - :status 404 Not Found: The deposit operation is unknown to the exchange - - **Details:** - - .. _tsref-type-TrackTransactionRequest: - .. _TrackTransactionRequest: - .. code-block:: tsref - - interface TrackTransactionRequest { - // SHA-512 hash of the merchant's payment details. - H_wire: HashCode; - - // SHA-512 hash of the contact of the merchant with the customer. - h_contract_terms: HashCode; - - // coin's public key, both ECDHE and EdDSA. - coin_pub: CoinPublicKey; - - // the EdDSA public key of the merchant, so that the client can identify - // the merchant for refund requests. - merchant_pub: EddsaPublicKey; - - // the EdDSA signature of the merchant made with purpose - // `TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION` , affirming that it is really the - // merchant who requires obtaining the wire transfer identifier. - merchant_sig: EddsaSignature; - } - - - .. _tsref-type-TrackTransactionResponse: - .. _TrackTransactionResponse: - .. code-block:: tsref - - interface TrackTransactionResponse { - // raw wire transfer identifier of the deposit. - wtid: Base32; - - // when was the wire transfer given to the bank. - execution_time: Timestamp; - - // The contribution of this coin to the total (without fees) - coin_contribution: Amount; - - // Total amount transferred - total_amount: Amount; - - // binary-only Signature_ for purpose `TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE` - // whereby the exchange affirms the successful wire transfer. - exchange_sig: EddsaSignature; - - // public EdDSA key of the exchange that was used to generate the signature. - // Should match one of the exchange's signing keys from /keys. Again given - // explicitly as the client might otherwise be confused by clock skew as to - // which signing key was used. - exchange_pub: EddsaPublicKey; - } - - .. _tsref-type-TrackTransactionAcceptedResponse: - .. _TrackTransactionAcceptedResponse: - .. code-block:: tsref - - interface TrackTransactionAcceptedResponse { - // time by which the exchange currently thinks the deposit will be executed. - execution_time: Timestamp; - } - - -------- -Refunds -------- - -.. _refund: -.. http:POST:: /refund - - Undo deposit of the given coin, restoring its value. - - **Request:** The request body must be a `RefundRequest`_ object. - - **Response:** - - :status 200 Ok: - The operation succeeded, the exchange confirms that the coin can now be refreshed. The response will include a `RefundSuccess`_ object. - :status 401 Unauthorized: - Merchant signature is invalid. - :status 404 Not found: - The refund operation failed as we could not find a matching deposit operation (coin, contract, transaction ID and merchant public key must all match). - :status 410 Gone: - It is too late for a refund by the exchange, the money was already sent to the merchant. - - **Details:** - - .. _RefundRequest: - .. code-block:: tsref - - interface RefundRequest { - - // Amount to be refunded, can be a fraction of the - // coin's total deposit value (including deposit fee); - // must be larger than the refund fee. - refund_amount: Amount; - - // Refund fee associated with the given coin. - // must be smaller than the refund amount. - refund_fee: Amount; - - // SHA-512 hash of the contact of the merchant with the customer. - h_contract_terms: HashCode; - - // coin's public key, both ECDHE and EdDSA. - coin_pub: CoinPublicKey; - - // 64-bit transaction id of the refund transaction between merchant and customer - rtransaction_id: number; - - // EdDSA public key of the merchant. - merchant_pub: EddsaPublicKey; - - // EdDSA signature of the merchant affirming the refund. - merchant_sig: EddsaPublicKey; - - } - - .. _RefundSuccess: - .. code-block:: tsref - - interface RefundSuccess { - // The string constant "REFUND_OK" - status: string; - - // the EdDSA :ref:`signature` (binary-only) with purpose - // `TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND` using a current signing key of the - // exchange affirming the successful refund - sig: EddsaSignature; - - // public EdDSA key of the exchange that was used to generate the signature. - // Should match one of the exchange's signing keys from /keys. It is given - // explicitly as the client might otherwise be confused by clock skew as to - // which signing key was used. - pub: EddsaPublicKey; - } - - ------------- -The Test API ------------- - -The test API is not there to test the exchange, but to allow -clients of the exchange (merchant and wallet implementations) -to test if their implemenation of the cryptography is -binary-compatible with the implementation of the exchange. - -.. http:POST:: /test/base32 - - Test hashing and Crockford :ref:`base32` encoding. - - **Request:** - - .. code-block:: tsref - - { - // some base32-encoded value - input: Base32; - } - - **Response:** - - .. code-block:: tsref - - { - // the base32_-encoded hash of the input value - output: Base32; - } - -.. http:POST:: /test/encrypt - - Test symmetric encryption. - - **Request:** - - .. code-block:: tsref - - { - // Some `base32`_-encoded value - input: Base32; - - // some `base32`_-encoded hash that is used to derive the symmetric key and - // initialization vector for the encryption using the HKDF with "skey" and - // "iv" as the salt. - key_hash: Base32; - } - - **Response:** - - - .. code-block:: tsref - - { - // the encrypted value - output: Base32; - } - -.. http:POST:: /test/hkdf - - Test Hash Key Deriviation Function. - - **Request:** - - - .. code-block:: tsref - - { - // Some `base32`_-encoded value - input: Base32; - } - - **Response:** - - - .. code-block:: tsref - - { - // the HKDF of the input using "salty" as salt - output: Base32; - } - -.. http:POST:: /test/ecdhe - - Test ECDHE. - - **Request:** - - .. code-block:: tsref - - { - ecdhe_pub: EcdhePublicKey; - ecdhe_priv: EcdhePrivateKey; - } - - **Response:** - - .. code-block:: tsref - - { - // ECDH result from the two keys - ecdhe_hash: HashCode; - } - - -.. http:POST:: /test/eddsa - - Test EdDSA. - - **Request:** - - .. code-block:: tsref - - { - eddsa_pub: EddsaPublicKey; - - // EdDSA signature using purpose TALER_SIGNATURE_CLIENT_TEST_EDDSA. Note: - // the signed payload must be empty, we sign just the purpose here. - eddsa_sig: EddsaSignature; - } - - **Response:** - - :status 200: the signature was valid - :status 401 Unauthorized: the signature was invalid - - The exchange responds with another valid signature, which gives the - client the opportunity to test its signature verification implementation. - - .. code-block:: tsref - - { - // Another EdDSA public key - eddsa_pub: EddsaPublicKey; - - // EdDSA signature using purpose TALER_SIGNATURE_EXCHANGE_TEST_EDDSA - eddsa_sig: EddsaSignature; - } - - -.. http:GET:: /test/rsa/get - - Obtain the RSA public key used for signing in /test/rsa/sign. - - **Response:** - - .. code-block:: tsref - - { - // The RSA public key the client should use when blinding a value for the /test/rsa/sign API. - rsa_pub: RsaPublicKey; - } - -.. http:POST:: /test/rsa/sign - - Test RSA blind signatures. - - **Request:** - - .. code-block:: tsref - - { - // Blinded value to sign. - blind_ev: BlindedRsaSignature; - } - - **Response:** - - - .. code-block:: tsref - - { - // Blind RSA signature over the `blind_ev` using the private key - // corresponding to the RSA public key returned by /test/rsa/get. - rsa_blind_sig: BlindedRsaSignature; - } - -.. http:POST:: /test/transfer - - Test Transfer decryption. - - **Request:** - - .. code-block:: tsref - - { - // Private transfer key - trans_priv: string; - - // `Coin public key `_ - coin_pub: EddsaPublicKey; - } - - **Response:** - - :status 200: the operation succeeded - - .. code-block:: tsref - - { - // Decrypted transfer secret - secret: string; - } diff --git a/api-merchant.rst b/api-merchant.rst deleted file mode 100644 index 9eb69812..00000000 --- a/api-merchant.rst +++ /dev/null @@ -1,1194 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014, 2015, 2016, 2017 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING. If not, see - - @author Marcello Stanisci - @author Florian Dold - @author Christian Grothoff - -.. _merchant-api: - -==================== -Merchant Backend API -==================== - ------------------- -Receiving Payments ------------------- - -.. _post-order: - -.. http:post:: /order - - Create a new order that a customer can pay for. - - This request is not idempotent unless an `order_id` is explicitly specified. - - .. note:: - - This endpoint does not return a URL to redirect your user to confirm the payment. - In order to get this URL use :http:get:`/check-payment`. The API is structured this way - since the payment redirect URL is not unique for every order, there might be varying parameters - such as the session id. - - **Request:** - - The request must be a `PostOrderRequest`_. - - **Response** - - :status 200 OK: - The backend has successfully created the proposal. The response is a - `PostOrderResponse`_. - - .. _PostOrderRequest: - .. code-block:: tsref - - interface PostOrderRequest { - // The order must at least contain the minimal - // order detail, but can override all - order: MinimalOrderDetail | ContractTerms; - } - - The following fields of the `ContractTerms`_ - - .. _MinimalOrderDetail: - .. _tsref-type-MinimalOrderDetail: - .. code-block:: tsref - - interface MinimalOrderRequest { - // Amount to be paid by the customer - amount: Amount - - // Short summary of the order - summary: string; - - // URL that will show that the order was successful after - // it has been paid for. The wallet will always automatically append - // the order_id as a query parameter. - fulfillment_url: string; - - // Merchant instance to use (leave empty to use instance "default") - instance?: string; - } - - .. _PostOrderResponse: - .. code-block:: tsref - - interface PostOrderResponse { - // Order ID of the response that was just created - order_id: string; - } - - -.. http:get:: /check-payment - - Check the payment status of an order. If the order exists but is not payed yet, - the response provides a redirect URL. - When the user goes to this URL, they will be prompted for payment. - - **Request:** - - :query order_id: order id that should be used for the payment - :query instance: *Optional*. Instance used for the payment. Defaults to the instance with identifier "default". - :query session_id: *Optional*. Session ID that the payment must be bound to. If not specified, the payment is not session-bound. - - **Response:** - - Returns a `CheckPaymentResponse`_, whose format can differ based on the status of the payment. - - .. _CheckPaymentResponse: - .. code-block:: tsref - - type CheckPaymentResponse = CheckPaymentPaidResponse | CheckPaymentUnpaidResponse - - .. _CheckPaymentPaidResponse: - .. _tsref-type-CheckPaymentPaidResponse: - .. code-block:: tsref - - interface CheckPaymentPaidResponse { - paid: true; - - // Was the payment refunded (even partially) - refunded: boolean; - - // Amount that was refunded - refund_amount: Amount; - - // Contract terms - contract_terms: ContractTerms; - } - - .. _CheckPaymentUnpaidResponse: - .. _tsref-type-CheckPaymentUnpaidResponse: - .. code-block:: tsref - - interface CheckPaymentUnpaidResponse { - paid: false; - - // URI that the wallet must process to complete the payment. - taler_pay_uri: string; - - } - - --------------- -Giving Refunds --------------- - - -.. http:post:: /refund - - Increase the refund amount associated with a given order. The user should be - redirected to the `refund_redirect_url` to trigger refund processing in the wallet. - - **Request** - - The request body is a `RefundRequest`_ object. - - **Response** - - :status 200 OK: - The refund amount has been increased, the backend responds with a `MerchantRefundResponse`_ - :status 400 Bad request: - The refund amount is not consistent: it is not bigger than the previous one. - - .. _RefundRequest: - .. code-block:: tsref - - interface RefundRequest { - // Order id of the transaction to be refunded - order_id: string; - - // Amount to be refunded - refund: Amount; - - // Human-readable refund justification - reason: string; - - // Merchant instance issuing the request - instance?: string; - } - - .. _MerchantRefundResponse: - .. code-block:: tsref - - interface MerchantRefundResponse { - // Public key of the merchant - merchant_pub: string; - - - // Contract terms hash of the contract that - // is being refunded. - h_contract_terms: string; - - // The signed refund permissions, to be sent to the exchange. - refund_permissions: MerchantRefundPermission[]; - - // URL (handled by the backend) that will - // trigger refund processing in the browser/wallet - refund_redirect_url: string; - } - - .. _MerchantRefundPermission: - .. _tsref-type-MerchantRefundPermissoin: - .. code-block:: tsref - - interface MerchantRefundPermission { - // Amount to be refunded. - refund_amount: AmountJson; - - // Fee for the refund. - refund_fee: AmountJson; - - // Public key of the coin being refunded. - coin_pub: string; - - // Refund transaction ID between merchant and exchange. - rtransaction_id: number; - - // Signature made by the merchant over the refund permission. - merchant_sig: string; - } - - --------------------- -Giving Customer Tips --------------------- - - -.. http:post:: /tip-authorize - - Authorize a tip that can be picked up by the customer's wallet by POSTing to - `/tip-pickup`. Note that this is simply the authorization step the back - office has to trigger first. The user should be navigated to the `tip_redirect_url` - to trigger tip processing in the wallet. - - **Request** - - The request body is a `TipCreateRequest`_ object. - - **Response** - - :status 200 OK: - A tip has been created. The backend responds with a `TipCreateConfirmation`_ - :status 404 Not Found: - The instance is unknown to the backend, expired or was never enabled or - the reserve is unknown to the exchange or expired (see detailed status - either being TALER_EC_RESERVE_STATUS_UNKNOWN or - TALER_EC_TIP_AUTHORIZE_INSTANCE_UNKNOWN or - TALER_EC_TIP_AUTHORIZE_INSTANCE_DOES_NOT_TIP or - TALER_EC_TIP_AUTHORIZE_RESERVE_EXPIRED. - :status 412 Precondition Failed: - The tip amount requested exceeds the available reserve balance for tipping. - - .. _TipCreateRequest: - .. code-block:: tsref - - interface TipCreateRequest { - // Amount that the customer should be tipped - amount: Amount; - - // Merchant instance issuing the request - instance?: string; - - // Justification for giving the tip - justification: string; - - // URL that the user should be directed to after tipping, - // will be included in the tip_token. - next_url: string; - } - - .. _TipCreateConfirmation: - .. code-block:: tsref - - interface TipCreateConfirmation { - // Token that will be handed to the wallet, - // contains all relevant information to accept - // a tip. - tip_token: string; - - // URL that will directly trigger procesing - // the tip when the browser is redirected to it - tip_redirect_url: string; - } - - -.. http:post:: /tip-query - - Query the status of an instance's tipping reserve. - - **Request** - - :query instance: instance to query - - **Response** - - :status 200 OK: - A tip has been created. The backend responds with a `TipQueryResponse`_ - :status 404 Not Found: - The instance is unknown to the backend. - :status 412 Precondition Failed: - The instance does not have a tipping reserve configured. - - .. _TipQueryResponse: - .. code-block:: tsref - - interface TipQueryResponse { - // Amount still available - amount_available: Amount; - - // Amount that we authorized for tips - amount_authorized: Amount; - - // Amount that was picked up by users already - amount_picked_up: Amount; - - // Timestamp indicating when the tipping reserve will expire - expiration: Timestamp; - - // Reserve public key of the tipping reserve - reserve_pub: string; - } - - ------------------------- -Tracking Wire Transfers ------------------------- - -.. http:get:: /track/transfer - - Provides deposits associated with a given wire transfer. - - **Request** - - :query wtid: raw wire transfer identifier identifying the wire transfer (a base32-encoded value) - :query wire_method: name of the wire transfer method used for the wire transfer - :query exchange: base URL of the exchange that made the wire transfer - :query instance: (optional) identificative token of the merchant `instance `_ which is being tracked. - - **Response:** - - :status 200 OK: - The wire transfer is known to the exchange, details about it follow in the body. - The body of the response is a `MerchantTrackTransferResponse`_. Note that - the similarity to the response given by the exchange for a /track/transfer - is completely intended. - - :status 404 Not Found: - The wire transfer identifier is unknown to the exchange. - - :status 424 Failed Dependency: The exchange provided conflicting information about the transfer. Namely, - there is at least one deposit among the deposits aggregated by `wtid` that accounts for a coin whose - details don't match the details stored in merchant's database about the same keyed coin. - The response body contains the `TrackTransferConflictDetails`_. - - .. _MerchantTrackTransferResponse: - .. _tsref-type-TrackTransferResponse: - .. code-block:: tsref - - interface TrackTransferResponse { - // Total amount transferred - total: Amount; - - // Applicable wire fee that was charged - wire_fee: Amount; - - // public key of the merchant (identical for all deposits) - merchant_pub: EddsaPublicKey; - - // hash of the wire details (identical for all deposits) - H_wire: HashCode; - - // Time of the execution of the wire transfer by the exchange - execution_time: Timestamp; - - // details about the deposits - deposits_sums: TrackTransferDetail[]; - - // signature from the exchange made with purpose - // `TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT` - exchange_sig: EddsaSignature; - - // public EdDSA key of the exchange that was used to generate the signature. - // Should match one of the exchange's signing keys from /keys. Again given - // explicitly as the client might otherwise be confused by clock skew as to - // which signing key was used. - exchange_pub: EddsaSignature; - } - - .. _tsref-type-TrackTransferDetail: - .. code-block:: tsref - - interface TrackTransferDetail { - // Business activity associated with the wire transferred amount - // `deposit_value`. - order_id: string; - - // The total amount the exchange paid back for `order_id`. - deposit_value: Amount; - - // applicable fees for the deposit - deposit_fee: Amount; - } - - - **Details:** - - .. _tsref-type-TrackTransferConflictDetails: - .. _TrackTransferConflictDetails: - .. code-block:: tsref - - interface TrackTransferConflictDetails { - // Numerical `error code `_ - code: number; - - // Text describing the issue for humans. - hint: String; - - // A /deposit response matching `coin_pub` showing that the - // exchange accepted `coin_pub` for `amount_with_fee`. - exchange_deposit_proof: DepositSuccess; - - // Offset in the `exchange_transfer_proof` where the - // exchange's response fails to match the `exchange_deposit_proof`. - conflict_offset: number; - - // The response from the exchange which tells us when the - // coin was returned to us, except that it does not match - // the expected value of the coin. - exchange_transfer_proof: TrackTransferResponse; - - // Public key of the coin for which we have conflicting information. - coin_pub: EddsaPublicKey; - - // Merchant transaction in which `coin_pub` was involved for which - // we have conflicting information. - transaction_id: number; - - // Expected value of the coin. - amount_with_fee: Amount; - - // Expected deposit fee of the coin. - deposit_fee: Amount; - - } - - -.. http:get:: /track/transaction - - Provide the wire transfer identifier associated with an (existing) deposit operation. - - **Request:** - - :query id: ID of the transaction we want to trace (an integer) - :query instance: merchant instance - - **Response:** - - :status 200 OK: - The deposit has been executed by the exchange and we have a wire transfer identifier. - The response body is a JSON array of `TransactionWireTransfer`_ objects. - :status 202 Accepted: - The deposit request has been accepted for processing, but was not yet - executed. Hence the exchange does not yet have a wire transfer identifier. - The merchant should come back later and ask again. - The response body is a :ref:`TrackTransactionAcceptedResponse `. Note that - the similarity to the response given by the exchange for a /track/order - is completely intended. - :status 404 Not Found: The transaction is unknown to the backend. - :status 424 Failed Dependency: - The exchange previously claimed that a deposit was not included in a wire - transfer, and now claims that it is. This means that the exchange is - dishonest. The response contains the cryptographic proof that the exchange - is misbehaving in the form of a `TransactionConflictProof`_. - - **Details:** - - .. _tsref-type-TransactionWireTransfer: - .. _TransactionWireTransfer: - .. code-block:: tsref - - interface TransactionWireTransfer { - - // Responsible exchange - exchange_uri: string; - - // 32-byte wire transfer identifier - wtid: Base32; - - // execution time of the wire transfer - execution_time: Timestamp; - - // Total amount that has been wire transfered - // to the merchant - amount: Amount; - } - - .. _tsref-type-CoinWireTransfer: - .. _CoinWireTransfer: - .. code-block:: tsref - - interface CoinWireTransfer { - // public key of the coin that was deposited - coin_pub: EddsaPublicKey; - - // Amount the coin was worth (including deposit fee) - amount_with_fee: Amount; - - // Deposit fee retained by the exchange for the coin - deposit_fee: Amount; - } - - .. _TransactionConflictProof: - .. _tsref-type-TransactionConflictProof: - .. code-block:: tsref - - interface TransactionConflictProof { - // Numerical `error code `_ - code: number; - - // Human-readable error description - hint: string; - - // A claim by the exchange about the transactions associated - // with a given wire transfer; it does not list the - // transaction that `transaction_tracking_claim` says is part - // of the aggregate. This is - // a `/track/transfer` response from the exchange. - wtid_tracking_claim: TrackTransferResponse; - - // The current claim by the exchange that the given - // transaction is included in the above WTID. - // (A response from `/track/order`). - transaction_tracking_claim: TrackTransactionResponse; - - // Public key of the coin for which we got conflicting information. - coin_pub: CoinPublicKey; - - } - - -------------------- -Transaction history -------------------- - -.. http:get:: /history - - Returns transactions up to some point in the past - - **Request** - - :query date: time threshold, see `delta` for its interpretation. - :query start: row number threshold, see `delta` for its interpretation. Defaults to `UINT64_MAX`, namely the biggest row id possible in the database. - :query delta: takes value of the form `N (-N)`, so that at most `N` values strictly younger (older) than `start` and `date` are returned. Defaults to `-20`. - :query instance: on behalf of which merchant instance the query should be accomplished. - :query ordering: takes value `descending` or `ascending` according to the results wanted from younger to older or vice versa. Defaults to `descending`. - - **Response** - - :status 200 OK: The response is a JSON `array` of `TransactionHistory`_. The array is sorted such that entry `i` is younger than entry `i+1`. - - .. _tsref-type-TransactionHistory: - .. _TransactionHistory: - .. code-block:: tsref - - interface TransactionHistory { - // The serial number this entry has in the merchant's DB. - row_id: number; - - // order ID of the transaction related to this entry. - order_id: string; - - // Transaction's timestamp - timestamp: Timestamp; - - // Total amount associated to this transaction. - amount: Amount; - } - -.. _proposal: - - -------------------------- -Dynamic Merchant Instance -------------------------- - -.. note:: - - The endpoints to dynamically manage merchant instances has not been - implemented yet. The bug id for this refernce is 5349. - -.. http:get:: /instances - - This is used to return the list of all the merchant instances - - **Response** - - :status 200 OK: - The backend has successfully returned the list of instances stored. Returns - a `InstancesResponse`_. - - .. _InstancesResponse: - .. code-block:: tsref - - interface InstancesResponse { - // List of instances that are present in the backend(see `below `_) - instances: Instance[]; - } - -The `instance` object describes the instance registered with the backend. It has the following structure: - - .. Instance: - .. _tsref-type-Instance: - .. code-block:: tsref - - interface Instance { - // Merchant name corresponding to this instance. - name: string; - - // The URL where the wallet will send coins. - payto: string; - - // Merchant instance of the response to create - instance: string; - - //unique key for each merchant - merchant_id: string; - } - - -.. http:put:: /instances/ - - This request will be used to create a new merchant instance in the backend. - - **Request** - - The request must be a `CreateInstanceRequest`_. - - **Response** - - :status 200 OK: - The backend has successfully created the instance. The response is a - `CreateInstanceResponse`_. - - .. _CreateInstanceRequest: - .. code-block:: tsref - - interface CreateInstanceRequest { - // The URL where the wallet has to send coins. - // payto://-URL of the merchant's bank account. Required. - payto: string; - - // Merchant instance of the response to create - // This field is optional. If it is not specified - // then it will automatically be created. - instance?: string; - - // Merchant name corresponding to this instance. - name: string; - - } - - .. _CreateInstanceResponse: - .. code-block:: tsref - - interface CreateInstanceResponse { - // Merchant instance of the response that was created - instance: string; - - //unique key for each merchant - merchant_id: string; - } - - -.. http:get:: /instances/ - - This is used to query a specific merchant instance. - - **Request:** - - :query instance_id: instance id that should be used for the instance - - **Response** - - :status 200 OK: - The backend has successfully returned the list of instances stored. Returns - a `QueryInstancesResponse`_. - - .. _QueryInstancesResponse: - .. code-block:: tsref - - interface QueryInstancesResponse { - // The URL where the wallet has to send coins. - // payto://-URL of the merchant's bank account. Required. - payto: string; - - // Merchant instance of the response to create - // This field is optional. If it is not specified - // then it will automatically be created. - instance?: string; - - // Merchant name corresponding to this instance. - name: string; - - } - - -.. http:post:: /instances/ - - This request will be used to update merchant instance in the backend. - - - **Request** - - The request must be a `PostInstanceUpdateRequest`_. - - **Response** - - :status 200 OK: - The backend has successfully updated the instance. The response is a - `PostInstanceUpdateResponse`_. - - .. _PostInstanceUpdateRequest: - .. code-block:: tsref - - interface PostInstanceUpdateRequest { - // Merchant instance that is to be updaated. Required. - instance: string; - - // New URL where the wallet has to send coins. - // payto://-URL of the merchant's bank account. Required. - payto: string; - - // Merchant name coreesponding to this instance. - name: string; - - } - - .. _PostInstanceUpdateResponse: - .. code-block:: tsref - - interface PostInstanceUpdateResponse { - // Merchant instance of the response that was updated - instance: string; - - //unique key for each merchant - merchant_id: string; - } - - -.. http:delete:: /instances/ - - This request will be used to delete merchant instance in the backend. - - **Request:** - - :query instance_id: instance id that should be used for the instance - - **Response** - - :status 200 OK: - The backend has successfully removed the instance. The response is a - `PostInstanceRemoveResponse`_. - - .. _PostInstanceRemoveResponse: - .. code-block:: tsref - - interface PostInstanceRemoveResponse { - deleted: true; - } - - ------------------- -The Contract Terms ------------------- - -The `contract terms` must have the following structure: - - .. _ContractTerms: - .. _tsref-type-ContractTerms: - .. code-block:: tsref - - interface ContractTerms { - // Human-readable description of the whole purchase - summary: string; - - // Unique, free-form identifier for the proposal. - // Must be unique within a merchant instance. - // For merchants that do not store proposals in their DB - // before the customer paid for them, the order_id can be used - // by the frontend to restore a proposal from the information - // encoded in it (such as a short product identifier and timestamp). - order_id: string; - - // Total price for the transaction. - // The exchange will subtract deposit fees from that amount - // before transfering it to the merchant. - amount: Amount; - - // The URL where the wallet has to send coins. - pay_url: string; - - // The URL for this purchase. Every time is is visited, the merchant - // will send back to the customer the same proposal. Clearly, this URL - // can be bookmarked and shared by users. - fulfillment_url: string; - - // Maximum total deposit fee accepted by the merchant for this contract - max_fee: Amount; - - // Maximum wire fee accepted by the merchant (customer share to be - // divided by the 'wire_fee_amortization' factor, and further reduced - // if deposit fees are below 'max_fee'). Default if missing is zero. - max_wire_fee: Amount; - - // Over how many customer transactions does the merchant expect to - // amortize wire fees on average? If the exchange's wire fee is - // above 'max_wire_fee', the difference is divided by this number - // to compute the expected customer's contribution to the wire fee. - // The customer's contribution may further be reduced by the difference - // between the 'max_fee' and the sum of the actual deposit fees. - // Optional, default value if missing is 1. 0 and negative values are - // invalid and also interpreted as 1. - wire_fee_amortization: Integer; - - // List of products that are part of the purchase (see `below `_) - products: Product[]; - - // Time when this contract was generated - timestamp: Timestamp; - - // After this deadline has passed, no refunds will be accepted. - refund_deadline: Timestamp; - - // After this deadline, the merchant won't accept payments for the contact - pay_deadline: Timestamp; - - // Merchant's public key used to sign this proposal; this information - // is typically added by the backend Note that this can be an ephemeral key. - merchant_pub: EddsaPublicKey; - - // More info about the merchant, see below - merchant: Merchant; - - // The hash of the merchant instance's wire details. - H_wire: HashCode; - - // Wire transfer method identifier for the wire method associated with H_wire. - // The wallet may only select exchanges via a matching auditor if the - // exchange also supports this wire method. - // The wire transfer fees must be added based on this wire transfer method. - wire_method: string; - - // Any exchanges audited by these auditors are accepted by the merchant. - auditors: Auditor[]; - - // Exchanges that the merchant accepts even if it does not accept any auditors that audit them. - exchanges: Exchange[]; - - // Map from labels to locations - locations: { [label: string]: [location: Location], ... }; - - // Nonce generated by the wallet and echoed by the merchant - // in this field when the proposal is generated. - nonce: string; - - // Extra data that is only interpreted by the merchant frontend. - // Useful when the merchant needs to store extra information on a - // contract without storing it separately in their database. - extra?: any; - } - - The wallet must select a exchange that either the mechant accepts directly by - listing it in the exchanges arry, or for which the merchant accepts an auditor - that audits that exchange by listing it in the auditors array. - - The `product` object describes the product being purchased from the merchant. It has the following structure: - - .. _Product: - .. _tsref-type-Product: - .. code-block:: tsref - - interface Product { - // Human-readable product description. - description: string; - - // The quantity of the product to deliver to the customer (optional, if applicable) - quantity?: string; - - // The price of the product; this is the total price for the amount specified by `quantity` - price: Amount; - - // merchant-internal identifier for the product - product_id?: string; - - // a list of objects indicating a `taxname` and its amount. Again, italics denotes the object field's name. - taxes?: any[]; - - // time indicating when this product should be delivered - delivery_date: Timestamp; - - // where to deliver this product. This may be an URL for online delivery - // (i.e. `http://example.com/download` or `mailto:customer@example.com`), - // or a location label defined inside the proposition's `locations`. - // The presence of a colon (`:`) indicates the use of an URL. - delivery_location: string; - } - - .. _tsref-type-Merchant: - .. code-block:: ts - - interface Merchant { - // label for a location with the business address of the merchant - address: string; - - // the merchant's legal name of business - name: string; - - // label for a location that denotes the jurisdiction for disputes. - // Some of the typical fields for a location (such as a street address) may be absent. - jurisdiction: string; - - // Which instance is working this proposal. - // See `Merchant Instances `_. - // This field is optional, as the "default" instance is not forced to provide any - // `instance` identificator. - instance: string; - } - - - .. _tsref-type-Location: - .. _Location: - .. code-block:: ts - - interface Location { - country?: string; - city?: string; - state?: string; - region?: string; - province?: string; - zip_code?: string; - street?: string; - street_number?: string; - } - - .. _tsref-type-Auditor: - .. code-block:: tsref - - interface Auditor { - // official name - name: string; - - // Auditor's public key - auditor_pub: EddsaPublicKey; - - // Base URL of the auditor - url: string; - } - - .. _tsref-type-Exchange: - .. code-block:: tsref - - interface Exchange { - // the exchange's base URL - url: string; - - // master public key of the exchange - master_pub: EddsaPublicKey; - } - - -------------------- -Customer-facing API -------------------- - -The `/public/*` endpoints are publicly exposed on the internet and accessed -both by the user's browser and their wallet. - - -.. http:post:: /public/pay - - Pay for a proposal by giving a deposit permission for coins. Typically used by - the customer's wallet. Can also be used in `abort-refund` mode to refund coins - that were already deposited as part of a failed payment. - - **Request:** - - The request must be a :ref:`pay request `. - - **Response:** - - :status 200 OK: - The exchange accepted all of the coins. The body is a `PaymentResponse`_ if the request used the mode "pay", or a `MerchantRefundResponse`_ if the request used was the mode "abort-refund". - The `frontend` should now fullfill the contract. - :status 412 Precondition Failed: - The given exchange is not acceptable for this merchant, as it is not in the - list of accepted exchanges and not audited by an approved auditor. - :status 401 Unauthorized: - One of the coin signatures was not valid. - :status 403 Forbidden: - The exchange rejected the payment because a coin was already spent before. - The response will include the `coin_pub` for which the payment failed, - in addition to the response from the exchange to the `/deposit` request. - - The `backend` will return verbatim the error codes received from the exchange's - :ref:`deposit ` API. If the wallet made a mistake, like by - double-spending for example, the `frontend` should pass the reply verbatim to - the browser/wallet. This should be the expected case, as the `frontend` - cannot really make mistakes; the only reasonable exception is if the - `backend` is unavailable, in which case the customer might appreciate some - reassurance that the merchant is working on getting his systems back online. - - .. _PaymentResponse: - .. code-block:: tsref - - interface PaymentResponse { - // Signature on `TALER_PaymentResponsePS`_ with the public - // key of the instance in the proposal. - sig: EddsaSignature; - - // Proposal data hash being signed over - h_proposal_data: HashCode; - - // Proposal, send for convenience so the frontend - // can do order processing without a second lookup on - // a successful payment - proposal: Proposal; - } - - - .. _tsref-type-Proposal: - .. code-block:: tsref - - interface Proposal { - // The proposal data, effectively the frontend's order with some data filled in - // by the merchant backend. - data: ProposalData; - - // Contract's hash, provided as a convenience. All components that do - // not fully trust the merchant must verify this field. - H_proposal: HashCode; - - // Signature over the hashcode of `proposal` made by the merchant. - merchant_sig: EddsaSignature; - } - - - .. _PayRequest: - .. code-block:: tsref - - interface PayRequest { - // Signature on `TALER_PaymentResponsePS`_ with the public - // key of the instance in the proposal. - sig: EddsaSignature; - - // Proposal data hash being signed over - h_proposal_data: HashCode; - - // Proposal, send for convenience so the frontend - // can do order processing without a second lookup on - // a successful payment - proposal: Proposal; - - // Coins with signature. - coins: CoinPaySig[]; - - // The merchant public key, used to uniquely - // identify the merchant instance. - merchant_pub: string; - - // Order ID that's being payed for. - order_id: string; - - // Mode for /pay ("pay" or "abort-refund") - mode: "pay" | "abort-refund"; - } - - -.. http:get:: /public/proposal - - Retrieve and take ownership (via nonce) over a proposal. - - **Request** - - :query instance: the merchant instance issuing the request - :query order_id: the order id whose refund situation is being queried - :query nonce: the nonce for the proposal - - **Response** - - :status 200 OK: - The backend has successfully retrieved the proposal. It responds with a :ref:`proposal `. - - :status 403 Forbidden: - The frontend used the same order ID with different content in the order. - - -.. http:post:: /public/tip-pickup - - Handle request from wallet to pick up a tip. - - **Request** - - The request body is a `TipPickupRequest`_ object. - - **Response** - - :status 200 OK: - A tip is being returned. The backend responds with a `TipResponse`_ - :status 401 Unauthorized: - The tip amount requested exceeds the tip. - :status 404 Not Found: - The tip identifier is unknown. - :status 409 Conflict: - Some of the denomination key hashes of the request do not match those currently available from the exchange (hence there is a conflict between what the wallet requests and what the merchant believes the exchange can provide). - - .. _TipPickupRequest: - .. code-block:: tsref - - interface TipPickupRequest { - - // Identifier of the tip. - tip_id: HashCode; - - // List of planches the wallet wants to use for the tip - planchets: PlanchetDetail[]; - } - - interface PlanchetDetail { - // Hash of the denomination's public key (hashed to reduce - // bandwidth consumption) - denom_pub_hash: HashCode; - - // coin's blinded public key - coin_ev: CoinEnvelope; - - } - - .. _TipResponse: - .. code-block:: tsref - - interface TipResponse { - // Public key of the reserve - reserve_pub: EddsaPublicKey; - - // The order of the signatures matches the planchets list. - reserve_sigs: EddsaSignature[]; - } - - -.. http:get:: /public/refund - - Pick up refunds for an order. - - **Request** - - :query instance: the merchant instance issuing the request - :query order_id: the order id whose refund situation is being queried - - **Response** - - If case of success, an *array of* `RefundLookup`_ objects is returned. - - .. _RefundLookup: - .. code-block:: tsref - - interface RefundLookup { - - // Coin from which the refund is going to be taken - coin_pub: EddsaPublicKey; - - // Refund amount taken from coin_pub - refund_amount: Amount; - - // Refund fee - refund_fee: Amount; - - // Identificator of the refund - rtransaction_id: number; - - // Merchant public key - merchant_pub: EddsaPublicKey - - // Merchant signature of a TALER_RefundRequestPS object - merchant_sig: EddsaSignature; - } - - -.. http:get:: /public/trigger-pay - - Used to trigger processing of payments, refunds and tips in the browser. The exact behavior - can be dependent on the user's browser. diff --git a/api-sync.rst b/api-sync.rst deleted file mode 100644 index 701c7df5..00000000 --- a/api-sync.rst +++ /dev/null @@ -1,407 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING. If not, see - - @author Christian Grothoff - -.. _sync-api: - -============================================= -Wallet Backup and Synchronization Service API -============================================= - -The wallet backup and synchronization service uses an EdDSA wallet key -to identify the "account" of the user. The wallet key is Crockford -Base32-encoded in the URI to access the data and used to sign requests -as well as to encrypt the contents (see below). These signatures are -provided in detached from as HTTP headers. - -Once the user activates backup or synchronization, the wallet should -display the wallet key as a QR code as well as in text format together -with the synchronization service's URL and ask the user to print this -key material and keep it safe. - -The actual format of the wallet database is not relevant for the -backup and synchronization service, as the service must only ever see -a padded and encrypted version of the data. - -However, there are a few general rules that will apply to -any version of the wallet database. Still, except for the -32 byte minimum upload size, the synchronization service -itself cannot not enforce these rules. - - * First, the database should be compressed (i.e. gzip), then - padded to a power of 2 in kilobytes or a multiple of - megabytes, then encrypted and finally protected with - an HDKF. - * The encryption should use an ephemeral Curve25519 point that - is prefixed to the actual database, and combined with - the private wallet key via ECDH to create a symmetric secret. - With every revision of the wallet (but only real - revisions or merge operations), a fresh ephemeral must be - used to ensure that the symmetric secret differs every - time. HKDFs are used to derive symmetric key material - for authenticated encryption (encrypt-then-mac or a - modern AEAD-cipher like Keccak). Given that AES is more - easily available and will likey increase the code of - the wallet less, AES plus a SHA-512 HMAC should suffice - for now. - * The wallet must enable merging databases in a way that is - associative and commutative. For most activities, this implies - merging lists, applying expirations, dropping duplicates and - sorting the result. For deletions (operations by which the user - removed records prior to their scheduled expiration), it means - keeping a summarizing log of all deletion operations and applying - the deletions after each merge. A summarizing log of a deletion - operation would combine two deletion operations of the form - "delete all transactions smaller than amount X before time T" and - "delete all transactions smaller than amount Y before time T" - into "delete all transactions smaller than amount max(X,Y) before - time T". Similar summarizations should be applied to all - deletion operations supported by the wallet. Deletion operations - themselves are associated with an expiration time reflecting the - expiration of the longest lasting record that they explicitly - deleted. - Purchases do not have an expiration time, thus they create - a challenge if an indivdiual purchase is deleted. Thus, when - an individual purchase is deleted, the wallet is to keep track - of the deletion with a deletion record. The deletion record - still includes the purchase amount and purchase date. Thus, - when purchases are deleted "in bulk" in a way that would have - covered the individual deletion, such deletion records may - still be subsumed by a more general deletion clause. In addition - to the date and amount, the deletion record should only contain - a salted hash of the original purchase record's primary key, - so as to minimize information leakage. - * The database should contain a "last modified" timestamp to ensure - we do not go backwards in time if the synchronization service is - malicious. Merging two databases means taking the max of the - "last modified" timestamps, not setting it to the current time. - The wallet should reject a "fast forward" database update if the - result would imply going back in time. If the wallet receives a - database with a timestamp into the future, it must still - increment it by the smallest possible amount when uploading an - update. - -It is assumed that the synchronization service is only ever accessed -over TLS, and that the synchronization service is trusted to not build -user's location profiles by linking client IP addresses and wallet -keys. - - --------------------------- -Receiving Terms of Service --------------------------- - -.. http:get:: /terms - - Obtain the terms of service provided by the storage service. - - **Response:** - - Returns a `SyncTermsOfServiceResponse`_. - - .. _SyncTermsOfServiceResponse: - .. _tsref-type-SyncTermsOfServiceResponse: - .. code-block:: tsref - - interface SyncTermsOfServiceResponse { - // maximum wallet database backup size supported - storage_limit_in_megabytes: number; - - // maximum number of sync requests per day (per account) - daily_sync_limit: number; - - // how long after an account (or device) becomes dormant does the - // service expire the respective records? - inactive_expiration: relative-time; - - // Fee for an account, per year. - annual_fee: Amount; - - } - - -.. http:get:: /salt - - Obtain the salt used by the storage service. - - - **Response:** - - Returns a `SaltResponse`_. - - .. _SaltResponse: - .. _tsref-type-SaltResponse: - .. code-block:: tsref - - interface SaltResponse { - // salt value, at least 128 bits of entropy - salt: string; - } - - -.. _sync: - -.. http:get:: /$WALLET-KEY - - Download latest version of the wallet database. - The returned headers must include "Etags" based on - the hash of the (encrypted) database. The server must - check the client's caching headers and only return the - full database if it has changed since the last request - of the client. - - This method is generally only performed once per device - when the private key and URL of a synchronization service are - first given to the wallet on the respective device. Once a - wallet has a database, it should always use the POST method. - - A signature is not required, as (1) the wallet-key should - be reasonably private and thus unauthorized users should not - know how to produce the correct request, and (2) the - information returned is encrypted to the private key anyway - and thus virtually useless even to an attacker who somehow - managed to obtain the public key. - - **Response** - - :status 200 OK: - The body contains the current version of the wallet's - database as known to the server. - - :status 204 No content: - This is a fresh account, no previous wallet data exists at - the server. - - :status 402 Payment required: - The synchronization service requires payment before the - account can continue to be used. The fulfillment URL - should be the /$WALLET-KEY URL, but can be safely ignored - by the wallet. The contract should be shown to the user - in the canonical dialog, possibly in a fresh tab. - - :status 410 Gone: - The backup service has closed operations. The body will - contain the latest version still available at the server. - The body may be empty if no version is available. - The user should be urged to find another provider. - - :status 429 Too many requests: - This account has exceeded daily thresholds for the number of - requests. The wallet should try again later, and may want - to decrease its synchronization frequency. - - .. note:: - - "200 OK" responses include an HTTP header - "X-Taler-Sync-Signature" with the signature of the - wallet from the orginal upload, and an - "X-Taler-Sync-Previous" with the version that was - being updated (unless this is the first revision). - "X-Taler-Sync-Previous" is only given to enable - signature validation. - - -.. http:post:: /$WALLET-KEY - - Upload a new version of the wallet's database, or download the - latest version. The request must include the "Expect: 100 Continue" - header. The client must wait for "100 Continue" before proceeding - with the upload, regardless of the size of the upload. - - **Request** - - The request must include a "If-Match" header indicating the latest - version of the wallet's database known to the client. If the server - knows a more recent version, it will respond with a "409 conflict" - and return the server's version in the response. The client must - then merge the two versions before retrying the upload. Note that - a "409 Conflict" response will typically be given before the upload, - (instead of "100 continue"), but may also be given after the upload, - for example due to concurrent activities from other wallets on the - same account! - - The request must also include an "X-Taler-Sync-Signature" signing - the "If-Match" SHA-512 value and the SHA-512 hash of the body with - the wallet private key. - - Finally, the SHA-512 hash of the body must also be given in an - "E-tag" header of the request (so that the signature can be verified - before the upload is allowed to proceed). We note that the use - of "E-tag" in HTTP requests is non-standard, but in this case - logical. - - The uploaded body must have at least 32 bytes of payload (see - suggested upload format beginning with an ephemeral key). - - - **Response** - - :status 204 No content: - The transfer was successful, and the server has registered - the new version. - - :status 304 Not modified: - The server is already aware of this version of the wallet. - Returned before 100 continue to avoid upload. - - :status 400 Bad request: - Most likely, the uploaded body is too short (less than 32 bytes). - - :status 401 Unauthorized: - The signature is invalid or missing (or body does not match). - - :status 402 Payment required: - The synchronization service requires payment before the - account can continue to be used. The fulfillment URL - should be the /$WALLET-KEY URL, but can be safely ignored - by the wallet. The contract should be shown to the user - in the canonical dialog, possibly in a fresh tab. - - :status 409 Conflict: - The server has a more recent version than what is given - in "If-Match". The more recent version is returned. The - client should merge the two versions and retry using the - given response's "E-Tag" in the next attempt in "If-Match". - - :status 410 Gone: - The backup service has closed operations. The body will - contain the latest version still available at the server. - The body may be empty if no version is available. - The user should be urged to find another provider. - - :status 411 Length required: - The client must specify the "Content-length" header before - attempting upload. While technically optional by the - HTTP specification, the synchronization service may require - the client to provide the length upfront. - - :status 413 Request Entity Too Large: - The requested upload exceeds the quota for the type of - account. The wallet should suggest to the user to - migrate to another backup and synchronization service - (like with "410 Gone"). - - :status 429 Too many requests: - This account has exceeded daily thresholds for the number of - requests. The wallet should try again later, and may want - to decrease its synchronization frequency. - - .. note:: - - Responses with a body include an HTTP header - "X-Taler-Sync-Signature" with the signature of the - wallet from the orginal upload, and an - "X-Taler-Sync-Previous" with the version that was - being updated (unless this is the first revision). - "X-Taler-Sync-Previous" is only given to enable - signature validation. - - - ---------------------------- -Special constraints for Tor ---------------------------- - -We might introduce the notion of a "constraint" into the wallet's -database that states that the database is a "Tor wallet". Then, -synchronizing a "Tor-wallet" with a non-Tor wallet should trigger a -stern warning and require user confirmation (as otherwise -cross-browser synchronization may weaken the security of Tor browser -users). - - ------------------------------------------------- -Discovery of backup and synchronization services ------------------------------------------------- - -The wallet should keep a list of "default" synchronization services -per currency (by the currency the synchronization service accepts -for payment). If a synchronization service is entirely free, it -should be kept in a special list that is always available. - -Extending (or shortening) the list of synchronization services should -be possible using the same mechanism that is used to add/remove -auditors or exchanges. - -The wallet should urge the user to make use of a synchronization -service upon first withdrawal, suggesting one that is free or -accepts payment in the respective currency. If none is available, -the wallet should warn the user about the lack of availalable -backups and synchronization and suggest to the user to find a -reasonable service. Once a synchronization service was selected, -the wallet should urge the user to print the respective key -material. - -When the wallet starts the first time on a new device, it should -ask the user if he wants to synchronize with an existing wallet, -and if so, ask the user to enter the respective key and the -(base) URL of the synchronization service. - - -------------------------- -Synchronization frequency -------------------------- - -Generally, the wallet should attempt to synchronize at a randomized -time interval between 30 and 300 seconds of being started, unless it -already synchronized less than two hours ago already. Afterwards, -the wallet should synchronize every two hours, or after purchases -exceed 5 percent of the last bulk amount that the user withdrew. -In all cases the exact time of synchronization should be randomized -between 30 and 300 seconds of the specified event, both to minimize -obvious correlations and to spread the load. - -If the two hour frequency would exceed half of the rate budget offered -by the synchronization provider, it should be reduced to remain below -that threshold. - - -------------------------------- -Synchronization user experience -------------------------------- - -The menu should include three entries for synchronization: - -* "synchronize" to manually trigger synchronization, - insensitive if no synchronization provider is available -* "export backup configuration" to re-display (and possibly - print) the synchronization and backup parameters (URL and - private key), insensitive if no synchronization - provider is available, and -* "import backup configuration" to: - - * import another devices' synchronization options - (by specifying URL and private key, or possibly - scanning a QR code), or - * select a synchronization provider from the list, - including manual specification of a URL; here - confirmation should only be possible if the provider - is free or can be paid for; in this case, the - wallet should trigger the payment interaction when - the user presses the "select" button. - * a special button to "disable synchronization and backup" - -One usability issue here is that we are asking users to deal with a -private key. It is likely better to map private keys to trustwords -(PEP-style). Also, when putting private keys into a QR code, there is -the danger of the QR code being scanned and interpreted as a "public" -URL. Thus, the QR code should use the schema -"taler-sync://$SYNC-DOMAIN/$SYNC-PATH#private-key" where -"$SYNC-DOMAIN" is the domainname of the synchronization service and -$SYNC-PATH the (usually empty) path. By putting the private key after -"#", we may succeed in disclosing the value even to eager Web-ish -interpreters of URLs. Note that the actual synchronization service -must use the HTTPS protocol, which means we can leave out this prefix. diff --git a/arch-api.dot b/arch-api.dot new file mode 100644 index 00000000..1c30c06a --- /dev/null +++ b/arch-api.dot @@ -0,0 +1,27 @@ +digraph G { + + user[label="Customer browser"]; + admin[label="Shop admin"]; + Backend[color="blue"]; + BackendPublic[color="blue", label="Backend\n(public interface)"]; + subgraph cluster_0 { + Frontend; + Backoffice; + Backend; + BackendPublic; + DBMS; + label="Shop server"; + } + subgraph cluster_1 { + Exchange; + label="Exchange"; + } + user->Frontend; + admin->Backoffice; + Frontend->Backend; + Backoffice->Backend; + BackendPublic->Backend; + user->BackendPublic; + Backend->DBMS; + Backend->Exchange; +} diff --git a/arch-api.png b/arch-api.png new file mode 100644 index 00000000..8004f790 Binary files /dev/null and b/arch-api.png differ diff --git a/arch.png b/arch.png new file mode 100644 index 00000000..37fc845b Binary files /dev/null and b/arch.png differ diff --git a/backoffice.rst b/backoffice.rst new file mode 100644 index 00000000..8dbfb165 --- /dev/null +++ b/backoffice.rst @@ -0,0 +1,155 @@ +Howtos for taler.net admins and developers (version 0.0.0, 16 Jan 2018), +Copyright © 2017-2018 Taler Systems SA. + + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 or + any later version published by the Free Software Foundation; with no + Invariant Sections, with no Front-Cover Texts, and with no Back-Cover + Texts. A copy of the license is included in the section entitled “GNU + Free Documentation License”. + +.. _Top: + +Back-office Web service manual +############################### + +Howtos for taler.net admins and developers (version 0.0.0, 16 Jan 2018), +Copyright © 2017-2018 Taler Systems SA. + + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 or + any later version published by the Free Software Foundation; with no + Invariant Sections, with no Front-Cover Texts, and with no Back-Cover + Texts. A copy of the license is included in the section entitled “GNU + Free Documentation License”. + +.. _Introduction: + +Introduction +============ + +The back-office Web service allows a merchant to check on the status of +their Taler transactions. Merchants can check if and when they were paid +by a wire transfer for coins deposited at the exchange. Also, given a +wire transfer they have received, they can ask which Taler transactions +correspond to the wire transfer. + +This manual guides merchant system administrators through the +installation and configuration of this Web service. + +.. _Installation: + +Installation +============ + +The back-office Web service code is available at +``git://taler.net/backoffice``. The application can be installed in a +GNU-ish fashion. + +:: + + # Get the code: + $ git clone git://taler.net/backoffice + + # Bootstrap and configure + $ cd backoffice + $ ./bootstrap + # This step will check if the system is ready to + # allow the installation. + $ ./configure --prefix= + $ make install + +Note that to make the application work ``/bin`` must be included +in the ``$PATH``, and ``/lib/python3.5/site-packages/`` in +``$PYTHONPATH``. + +.. _Configuration: + +Configuration +============= + +The following information must be provided in the configuration: on +which address the backend should serve the Web site, which currency is +used, and which merchant backend this Web service will work with. + +The merchant backend is an important agent, as it is responsible for +returning information about transactions and wire transfers. The +backoffice Web service is merely a frontend for it. A separate manual +(available at https://docs.taler.net/merchant/backend/html/manual.html) +describes the installation and configuration of the merchant backend. + +Assuming the reader is familiar with configuration in Taler (if not, +read: +https://docs.taler.net/exchange/html/taler-exchange.html#Configuration-format), +a working configuration example is the following one: + +:: + + [taler] + # will be EUR, USD, or whatever currency the merchant + # works with. + currency = KUDOS + + # each back-office Web service is associated with a "frontend + # name": this name instructs the application which configuration + # section is going to be read. Thus is the "frontend name" + # and must be specified on the command line via the "--frontend" + # option. See the 'Run' chapter for more details on launching the + # application. + [backoffice-] + + # This option sets the way the backoffice communicates + # when it is instructed to operate via UWSGI. Therefore, + # can be: TCP or UNIX. If TCP is given, then the + # additional UWSGI_PORT option becomes necessary. + uwsgi_serve = + + # those options will be read if the Web site is served via + # WSGI. + uwsgi_unixpath_mode = 660 + uwsgi_unixpath = /path/to/backoffice-.uwsgi + uwsgi_unixmode = 666 + + # If UWSGI_SERVE were set as 'TCP', then the following option + # would have been necessary. It instructs the backoffice service + # about which TCP port should be listened on, to communicate over + # UWSGI. + # uwsgi_port = 8080 + + # this option will be read if the Web site is served via + # HTTP. + http_port = 5959 + + # specifies which merchant backend is going to be used. + backend = http://backend.test.taler.net/ + + # Informally speaking, each instance points to both a private + # key that can sign proposals and a bank account that can receive + # wire transfers by some exchange. + + # Here, is just a string (with no spaces) that will + # make the referenced instance be traceable by the back-office Web + # application. + + instances = .. + +.. _Launching-the-backoffice: + +Launching the backoffice +======================== + +The following example shows how to run the Web service. + +:: + + # such invocation will work only if the configuration contains + # a section called "[backoffice-myshop]" which looks like the + # example above. + + # As of serving, the Web site will be available via HTTP, at the + # port specified in the configuration option "http_port", at localhost. + + $ taler-merchant-backoffice --frontend myshop serve-http + +Other options, such as those to serve the site via WSGI, are explained +in the man page and can be listed using the ``--help`` argument. diff --git a/conf.py b/conf.py index eacad348..bfc817dc 100644 --- a/conf.py +++ b/conf.py @@ -136,6 +136,7 @@ html_sidebars = { html_theme_options = { # Set the name of the project to appear in the sidebar "project_nav_name": "GNU Taler", + "globaltoc_depth": 4, } # Add any paths that contain custom themes here, relative to this directory. diff --git a/core/api-auditor.rst b/core/api-auditor.rst new file mode 100644 index 00000000..957b1c01 --- /dev/null +++ b/core/api-auditor.rst @@ -0,0 +1,232 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING. If not, see + + @author Christian Grothoff + +============================ +The Auditor RESTful JSON API +============================ + +The API specified here follows the :ref:`general conventions ` +for all details not specified in the individual requests. +The `glossary ` +defines all specific terms used in this section. + +.. _auditor-version: + +------------------------- +Obtaining Auditor Version +------------------------- + +This API is used by merchants to obtain a list of all exchanges audited by +this auditor. This may be required for the merchant to perform the required +know-your-customer (KYC) registration before issuing contracts. + +.. http:get:: /version + + Get the protocol version and some meta data about the auditor. + + **Response:** + + :status 200 OK: + The auditor responds with a `AuditorVersion`_ object. This request should + virtually always be successful. + + **Details:** + + .. _AuditorVersion: + .. code-block:: tsref + + interface AuditorVersion { + // libtool-style representation of the Taler protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". Note that the auditor + // protocol is versioned independently of the exchange's protocol. + version: String; + + // Return which currency this auditor is auditing for. + currency: String; + + // EdDSA master public key of the auditor + auditor_public_key: EddsaPublicKey; + } + + .. note:: + + This API is still experimental (and is not yet implemented at the + time of this writing). + + +.. _exchange-list: + +----------------------- +Obtaining Exchange List +----------------------- + +This API is used by merchants to obtain a list of all exchanges audited by +this auditor. This may be required for the merchant to perform the required +know-your-customer (KYC) registration before issuing contracts. + +.. http:get:: /exchanges + + Get a list of all exchanges audited by the auditor. + + **Response:** + + :status 200 OK: + The auditor responds with a `ExchangeList`_ object. This request should + virtually always be successful. + + **Details:** + + .. _ExchangeList: + .. code-block:: tsref + + interface ExchangeList { + // Exchanges audited by this auditor + exchanges: ExchangeEntry[]; + } + + .. _tsref-type-Denom: + .. code-block:: tsref + + interface ExchangeEntry { + + // Master public key of the exchange + master_pub: EddsaPublicKey; + + // Base URL of the exchange + exchange_url: string; + } + + .. note:: + + This API is still experimental (and is not yet implemented at the + time of this writing). A key open question is whether the auditor + should sign the information. We might also want to support more + delta downloads in the future. + +.. _deposit-confirmation: + +-------------------------------- +Submitting deposit confirmations +-------------------------------- + +Merchants should probabilistically submit some of the deposit +confirmations they receive from the exchange to auditors to ensure +that the exchange does not lie about recording deposit confirmations +with the exchange. Participating in this scheme ensures that in case +an exchange runs into financial trouble to pay its obligations, the +merchants that did participate in detecting the bad behavior can be +paid out first. + +.. http:put:: /deposit-confirmation + + Submits a `DepositConfirmation`_ to the exchange. Should succeed + unless the signature provided is invalid or the exchange is not + audited by this auditor. + + **Response:** + + :status 200: The auditor responds with a `DepositAudited`_ object. + This request should virtually always be successful. + + **Details:** + + .. _DepositAudited: + .. _tsref-type-DepositAudited: + .. code-block:: tsref + + interface DepositAudited { + // TODO: do we care for the auditor to sign this? + } + + .. _DepositConfirmation: + .. _tsref-type-DepositConfirmation: + .. code-block:: tsref + + interface DepositConfirmation { + + // Hash over the contract for which this deposit is made. + h_contract_terms: HashCode; + + // Hash over the wiring information of the merchant. + h_wire: HashCode; + + // Time when the deposit confirmation confirmation was generated. + timestamp: Timestamp; + + // How much time does the merchant have to issue a refund + // request? Zero if refunds are not allowed. + refund_deadline : Timestamp; + + // Amount to be deposited, excluding fee. Calculated from the + // amount with fee and the fee from the deposit request. + amount_without_fee: Amount; + + // The coin's public key. This is the value that must have been + // signed (blindly) by the Exchange. The deposit request is to be + // signed by the corresponding private key (using EdDSA). + coin_pub: CoinPublicKey; + + // The Merchant's public key. Allows the merchant to later refund + // the transaction or to inquire about the wire transfer identifier. + merchant_pub: EddsaPublicKey; + + // Signature from the exchange of type + // TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT. + exchange_sig: EddsaSignature; + + // Public signing key from the exchange matching @e exchange_sig. + exchange_pub: EddsaPublicKey; + + // Master public key of the exchange corresponding to @e master_sig. + // Identifies the exchange this is about. + master_pub: EddsaPublicKey; + + // When does the validity of the exchange_pub end? + ep_start: Timestamp; + + // When will the exchange stop using the signing key? + ep_expire: Timestamp; + + // When does the validity of the exchange_pub end? + ep_end: Timestamp; + + // Exchange master signature over @e exchange_sig. + master_sig: EddsaSignature; + } + + .. note:: + + This API is still experimental (and is not yet implemented at the + time of this writing). A key open question is whether the auditor + should sign the response information. + + +---------- +Complaints +---------- + +This API is used by the wallet or merchants to submit proof of +misbehavior of an exchange to the auditor. + + .. note:: + + To be designed and implemented. + + .. http:put:: /complain + + Complain about missbehavior to the auditor. diff --git a/core/api-bank.rst b/core/api-bank.rst new file mode 100644 index 00000000..a3c8953e --- /dev/null +++ b/core/api-bank.rst @@ -0,0 +1,392 @@ +.. + This file is part of GNU TALER. + + Copyright (C) 2014, 2015, 2016, 2017 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see + + @author Marcello Stanisci + @author Christian Grothoff + +========= +Bank API +========= + +This API provides programmatic user registration at the bank. + +.. _bank-register: +.. http:post:: /register + +**Request** The body of this request must have the format of a `BankRegistrationRequest`_. + +**Response** + +:status 200 OK: The new user has been correctly registered. +:status 409 Conflict: the username requested by the client is not available anymore +:status 406 Not Acceptable: unacceptable characters were given for the username. See https://docs.djangoproject.com/en/2.2/ref/contrib/auth/#django.contrib.auth.models.User.username for the accepted character set. + +**Details** + +.. _BankRegistrationRequest: +.. code-block:: tsref + + interface BankRegistrationRequest { + + // Username to use for registration; max length is 150 chars. + username: string; + + // Password to associate with the username. Any characters and + // any length are valid; next releases will enforce a minimum length + // and a safer characters choice. + password: string; + } + + +This API provides programmatic withdrawal of cash via Taler to all the +users registered at the bank. It triggers a wire transfer from the client +bank account to the exchange's. + +.. _bank-withdraw: +.. http:post:: /taler/withdraw + +**Request** The body of this request must have the format of a `BankTalerWithdrawRequest`_. + +**Response** + +:status 200 OK: The withdrawal was correctly initiated, therefore the exchange received the payment. A `BankTalerWithdrawResponse`_ object is returned. +:status 406 Not Acceptable: the user does not have sufficient credit to fulfill their request. +:status 404 Not Found: The exchange wire details did not point to any valid bank account. + +**Details** + +.. _BankTalerWithdrawRequest: +.. code-block:: tsref + + interface BankTalerWithdrawRequest { + + // Authentication method used + auth: BankAuth; + + // Amount to withdraw. + amount: Amount; + + // Reserve public key. + reserve_pub: string; + + // Exchange bank details specified in the 'payto' + // format. NOTE: this field is optional, therefore + // the bank will initiate the withdrawal with the + // default exchange, if not given. + exchange_wire_details: string; + } + +.. _BankTalerWithdrawResponse: +.. code-block:: tsref + + interface BankTalerWithdrawResponse { + + // Sender account details in 'payto' format. + sender_wire_details: string; + + // Exchange base URL. Optional: only returned + // if the user used the default exchange. + exchange_url: string; + } + +This API allows one user to send money to another user, within the same "test" +bank. The user calling it has to authenticate by including his credentials in the +request. + +.. _bank-deposit: +.. http:post:: /admin/add/incoming + +**Request:** The body of this request must have the format of a `BankDepositRequest`_. + +**Response:** + +:status 200 OK: The request has been correctly handled, so the funds have been transferred to the recipient's account. The body is a `BankDepositDetails`_. +:status 400 Bad Request: The bank replies a `BankError`_ object. +:status 406 Not Acceptable: The request had wrong currency; the bank replies a `BankError`_ object. + +**Details:** + +.. _BankDepositDetails: +.. code-block:: tsref + + interface BankDepositDetails { + + // Timestamp related to the transaction being made. + timestamp: Timestamp; + + // Row id number identifying the transaction in the bank's + // database. + row_id: number; + } + +.. _BankDepositRequest: +.. code-block:: tsref + + interface BankDepositRequest { + + // Authentication method used + auth: BankAuth; + + // JSON 'amount' object. The amount the caller wants to transfer + // to the recipient's count + amount: Amount; + + // Exchange base URL, used to perform tracking requests against the + // wire transfer ID. Note that in the actual bank wire transfer, + // the schema may have to be encoded differently, i.e. + // "https://exchange.com/" may become "https exchange.com" due to + // character set restrictions. It is the responsibility of the + // wire transfer adapter to properly encode/decode the URL. + // Payment service providers must ensure that their URL is short + // enough to fit together with the wire transfer identifier into + // the wire transfer subject of their respective banking system. + exchange_url: string; + + // The subject of this wire transfer. + subject: string; + + // The sender's account identificator. NOTE, in the current stage + // of development this field is _ignored_, as it's always the bank account + // of the logged user that plays as the "debit account". + // In future releases, a logged user may specify multiple bank accounts + // of her/his as the debit account. + debit_account: number; + + // The recipient's account identificator + credit_account: number; + + } + +.. _BankAuth: +.. _tsref-type-BankAuth: +.. code-block:: tsref + + interface BankAuth { + + // authentication type. At this stage of development, + // only value "basic" is accepted in this field. + // The credentials must be indicated in the following HTTP + // headers: "X-Taler-Bank-Username" and "X-Taler-Bank-Password". + type: string; + } + + +.. _BankError: +.. code-block:: tsref + + interface BankError { + + // Human readable explanation of the failure. + error: string; + + // Numeric Taler error code (`enum TALER_ErrorCode`) + ec: number; + + } + + +.. http:put:: /reject + + Rejects an inbound transaction. This can be used by the receiver of a wire transfer to + cancel that transaction, nullifying its effect. This basically creates a correcting + entry that voids the original transaction. Henceforth, the /history must show + the original transaction as "cancelled+" or "cancelled-" for creditor and debitor respectively. + This API is used when the exchange receives a wire transfer with an invalid wire + transfer subject that fails to decode to a public key. + + **Request** The body of this request must have the format of a `BankCancelRequest`_. + + :query auth: authentication method used. At this stage of development, only value `basic` is accepted. Note that username and password need to be given as request's headers. The dedicated headers are: `X-Taler-Bank-Username` and `X-Taler-Bank-Password`. + :query row_id: row identifier of the transaction that should be cancelled. + :query account_number: bank account for which the incoming transfer was made and for which `auth` provides the authentication data. *Currently ignored*, as multiple bank accounts per user are not implemented yet. + + .. _BankCancelRequest: + .. code-block:: tsref + + interface BankCancelRequest { + + // Authentication method used + auth: BankAuth; + + // The row id of the wire transfer to cancel + row_id: number; + + // The recipient's account identificator + credit_account: number; + + } + + **Response** In case of an error, the body is a `BankError`_ object. + + :status 204 No Content: The request has been correctly handled, so the original transaction was voided. The body is empty. + :status 400 Bad Request: The bank replies a `BankError`_ object. + :status 404 Not Found: The bank does not know this rowid for this account. + + +.. http:get:: /history-range + + Filters and returns the list of transactions in the time range specified by `start` and `end` + + **Request** + + :query auth: authentication method used. At this stage of development, only value `basic` is accepted. Note that username and password need to be given as request's headers. The dedicated headers are: `X-Taler-Bank-Username` and `X-Taler-Bank-Password`. + :query start: unix timestamp indicating the oldest transaction accepted in the result. + :query end: unix timestamp indicating the youngest transaction accepted in the result. + :query direction: argument taking values `debit` or `credit`, according to the caller willing to receive both incoming and outgoing, only outgoing, or only incoming records. Use `both` to return both directions. + :query cancelled: argument taking values `omit` or `show` to filter out rejected transactions + :query account_number: bank account whose history is to be returned. *Currently ignored*, as multiple bank accounts per user are not implemented yet. + :query ordering: can be `descending` or `ascending` and regulates whether the row are returned youger-to-older or vice versa. Defaults to `descending`. + + + **Response** + + :status 200 OK: JSON object whose field `data` is an array of type `BankTransaction`_. + :status 204 No content: in case no records exist for the targeted user. + + +.. http:get:: /history + + Filters and returns the list of transactions of the customer specified in the request. + + **Request** + + :query auth: authentication method used. At this stage of development, only value `basic` is accepted. Note that username and password need to be given as request's headers. The dedicated headers are: `X-Taler-Bank-Username` and `X-Taler-Bank-Password`. + :query delta: returns the first `N` records younger (older) than `start` if `+N` (`-N`) is specified. + :query start: according to `delta`, only those records with row id strictly greater (lesser) than `start` will be returned. This argument is optional; if not given, it defaults to "MAX_UINT64". + :query direction: argument taking values `debit` or `credit`, according to the caller willing to receive both incoming and outgoing, only outgoing, or only incoming records. Use `both` to return both directions. + :query cancelled: argument taking values `omit` or `show` to filter out rejected transactions + :query account_number: bank account whose history is to be returned. *Currently ignored*, as multiple bank accounts per user are not implemented yet. + :query ordering: can be `descending` or `ascending` and regulates whether the row are returned youger-to-older or vice versa. Defaults to `descending`. + + + **Response** + + :status 200 OK: JSON object whose field `data` is an array of type `BankTransaction`_. + :status 204 No content: in case no records exist for the targeted user. + +.. _BankTransaction: +.. code-block:: tsref + + interface BankTransaction { + + // identification number of the record + row_id: number; + + // Date of the transaction + date: Timestamp; + + // Amount transferred + amount: Amount; + + // "-" if the transfer was outgoing, "+" if it was + // incoming; "cancel+" or "cancel-" if the transfer + // was /reject-ed by the receiver. + sign: string; + + // Bank account number of the other party involved in the + // transaction. + counterpart: number; + + // Wire transfer subject line. + wt_subject: string; + + } + +.. + The counterpart currently only points to the same bank as + the client using the bank. A reasonable improvement is to + specify a bank URL too, so that Taler can run across multiple + banks. + +------------------------ +Interactions with wallet +------------------------ + +A bank and a wallet need to communicate for (1) make some elements visible +only if the wallet is installed, (2) exchange information when the user withdraws +coins. + +Make elements visible. +^^^^^^^^^^^^^^^^^^^^^^ + +This feature works via CSS injection from the wallet. To enable it, the +page must contain the ```` element, so that +the wallet will do the injection. + +Whenever a element ```` needs to be visualized (hidden) if the wallet is +installed, the special class ``taler-installed-show`` (``taler-installed-hide``) +must be added to ``x``, as follows: + +* ``y`` will make ``y`` visible. +* ``y`` will make ``y`` visible. + +Clearly, a fallback page must be provided, which will be useful if the +wallet is *not* installed. This special page will hide any element of +the class ``taler-install-show``; it can be downloaded at the following +URL: ``git://taler.net/web-common/taler-fallback.css``. + +Withdrawing coins. +^^^^^^^^^^^^^^^^^^ + +After the user confirms the withdrawal, the bank must return a `202 Accepted` response, +along with the following HTTP headers: + +* ``X-Taler-Operation: create-reserve`` +* ``X-Taler-Callback-Url: ``; this URL will be automatically visited by the wallet after the user confirms the exchange. +* ``X-Taler-Wt-Types: '["test"]'``; stringified JSON list of supported wire transfer types (only 'test' supported so far). +* ``X-Taler-Amount: ``; stringified Taler-style JSON :ref:`amount `. +* ``X-Taler-Sender-Wire: ``; stringified WireDetails_. +* ``X-Taler-Suggested-Exchange: ``; this header is optional, and ```` is the suggested exchange URL as given in the `SUGGESTED_EXCHANGE` configuration option. + +.. _WireDetails: +.. code-block:: tsref + + interface WireDetails { + type: string; // Only 'test' value admitted so far. + bank_uri: URL of the bank. + account_number: bank account number of the user attempting to withdraw. + } + +After the user confirms the exchange to withdraw coins from, the wallet will +visit the callback URL, in order to let the user answer some security questions +and provide all relevant data to create a reserve. + +.. note:: + Currently, the bank is in charge of creating the reserve at the chosen + exchange. In future, the exchange will "poll" its bank account and automatically + creating a reserve whenever it receives any funds, without any bank's + intervention. + +The callback URL implements the following API. + +.. http:get:: + + **Request** + + :query amount_value: integer part of the amount to be withdrawn. + :query amount_fraction: fractional part of the amount to be withdrawn. + :query amount_currency: currency of the amount to be withdrawn. + :query exchange: base URL of the exchange where the reserve is to be created. + :query reserve_pub: public key of the reserve to create. + :query exchange_wire_details: stringification of the chosen exchange's WireDetails_. + + **Response** + + Because the wallet is not supposed to take action according to this response, + the bank implementers are not required to return any particular status code here. + + For example, our demonstrator bank always redirects the browser to the user's + profile page and let them know the outcome via a informational bar. diff --git a/core/api-common.rst b/core/api-common.rst new file mode 100644 index 00000000..8f3ae378 --- /dev/null +++ b/core/api-common.rst @@ -0,0 +1,812 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016 GNUnet e.V. and INRIA + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU 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 Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING. If not, see + + @author Christian Grothoff + @author Marcello Stanisci + +.. _http-common: + +================================= +Common Taler HTTP API Conventions +================================= + + +------------------------- +HTTP Request and Response +------------------------- + +Certain response formats are common for all requests. They are documented here +instead of with each individual request. Furthermore, we note that clients may +theoretically fail to receive any response. In this case, the client should +verify that the Internet connection is working properly, and then proceed to +handle the error as if an internal error (500) had been returned. + +.. http:any:: /* + + + **Request:** + + Unless specified otherwise, HTTP requests that carry a message body must + have the content type `application/json`. + + :reqheader Content-Type: application/json + + **Response:** + + :resheader Content-Type: application/json + :status 200: The request was successful. + :status 500 Internal server error: + This always indicates some serious internal operational error of the exchange, + such as a program bug, database problems, etc., and must not be used for + client-side problems. When facing an internal server error, clients should + retry their request after some delay. We recommended initially trying after + 1s, twice more at randomized times within 1 minute, then the user should be + informed and another three retries should be scheduled within the next 24h. + If the error persists, a report should ultimately be made to the auditor, + although the auditor API for this is not yet specified. However, as internal + server errors are always reported to the exchange operator, a good operator + should naturally be able to address them in a timely fashion, especially + within 24h. When generating an internal server error, the exchange responds with + a JSON object containing the following fields: + :status 400 Bad Request: One of the arguments to the request is missing or malformed. + + Unless specified otherwise, all error status codes (4xx and 5xx) have a message + body with an `ErrorDetail`_ JSON object. + + **Details:** + + .. _ErrorDetail: + .. _tsref-type-ErrorDetail: + .. code-block:: tsref + + interface ErrorDetail { + + // Numeric `error code `_ unique to the condition. + code: number; + + // Human-readable description of the error, i.e. "missing parameter", "commitment violation", ... + // The other arguments are specific to the error value reported here. + error: string; + + // Hint about error nature + hint?: string; + + // Name of the parameter that was bogus (if applicable) + parameter?: string; + + // Path to the argument that was bogus (if applicable) + path?: string; + + // Offset of the argument that was bogus (if applicable) + offset?: string; + + // Index of the argument that was bogus (if applicable) + index?: string; + + // Name of the object that was bogus (if applicable) + object?: string; + + // Name of the currency thant was problematic (if applicable) + currency?: string; + + // Expected type (if applicable). + type_expected?: string; + + // Type that was provided instead (if applicable). + type_actual?: string; + } + + +.. _encodings-ref: + +---------------- +Common encodings +---------------- + +This section describes how certain types of values are represented throughout the API. + +.. _base32: +.. _tsref-type-Base32: + +Binary Data +^^^^^^^^^^^ + +Binary data is generally encoded using Crockford's variant of Base32 +(http://www.crockford.com/wrmg/base32.html), except that "U" is not excluded +but also decodes to "V" to make OCR easy. We will still simply use the JSON +type "base32" and the term "Crockford Base32" in the text to refer to the +resulting encoding. + +.. _tsref-type-HashCode: + +Hash codes +^^^^^^^^^^ +Hashcodes are strings representing base32 encoding of the respective hashed +data. See `base32`_. + +Large numbers +^^^^^^^^^^^^^ + +Large numbers such as RSA blinding factors and 256 bit keys, are transmitted +as other binary data in Crockford Base32 encoding. + + +.. _tsref-type-Timestamp: + +Timestamps +^^^^^^^^^^ + +Timestamps are represented in JSON as a string literal `"\\/Date(x)\\/"`, +where `x` is the decimal representation of the number of seconds past the +Unix Epoch (January 1, 1970). The escaped slash (`\\/`) is interpreted in +JSON simply as a normal slash, but distinguishes the timestamp from a normal +string literal. We use the type "date" in the documentation below. +Additionally, the special strings "\\/never\\/" and "\\/forever\\/" are +recognized to represent the end of time. + + +.. _public\ key: + +Keys +^^^^ + +.. _`tsref-type-EddsaPublicKey`: +.. _`tsref-type-EcdhePublicKey`: +.. _`tsref-type-EcdhePrivateKey`: +.. _`tsref-type-EddsaPrivateKey`: +.. _`tsref-type-CoinPublicKey`: + +.. code-block:: tsref + + // EdDSA and ECDHE public keys always point on Curve25519 + // and represented using the standard 256 bits Ed25519 compact format, + // converted to Crockford `Base32`_. + type EddsaPublicKey = string; + type EddsaPrivateKey = string; + +.. _`tsref-type-RsaPublicKey`: + +.. code-block:: tsref + + // RSA public key converted to Crockford `Base32`_. + type RsaPublicKey = string; + +.. _blinded-coin: + +Blinded coin +^^^^^^^^^^^^ + +.. _`tsref-type-CoinEnvelope`: + +.. code-block:: tsref + + // Blinded coin's `public EdDSA key `_, `base32`_ encoded + type CoinEnvelope = string; + +.. _signature: + +Signatures +^^^^^^^^^^ + +.. _`tsref-type-EddsaSignature`: + +.. code-block:: tsref + + // EdDSA signatures are transmitted as 64-bytes `base32`_ + // binary-encoded objects with just the R and S values (base32_ binary-only) + type EddsaSignature = string; + + +.. _`tsref-type-RsaSignature`: + +.. code-block:: tsref + + // `base32`_ encoded RSA signature + type RsaSignature = string; + +.. _`tsref-type-BlindedRsaSignature`: + +.. code-block:: tsref + + // `base32`_ encoded RSA blinded signature + type BlindedRsaSignature = string; + +.. _amount: + +Amounts +^^^^^^^ + +.. _`tsref-type-Amount`: + +Amounts of currency are serialized as a string of the format `:`. +Taler treats monetary amounts as fixed-precision numbers. Unlike floating point numbers, +this allows accurate representation of monetary amounts. + +The following constrains apply for a valid amount: + +1. The `` part must be at most 12 characters long and may not contain a colon (`:`). +2. The integer part of `` may be at most 2^52 +3. the fractional part of `` may contain at most 8 decimal digits. + +Internally, amounts are parsed into the following object: + +.. note:: + + "EUR:1.50" and "EUR:10" are is a valid amounts. These are all invalid amounts: "A:B:1.5", "EUR:4503599627370501.0", "EUR:1.", "EUR:.1" + +.. code-block:: tsref + + interface ParsedAmount { + // name of the currency using either a three-character ISO 4217 currency + // code, or a regional currency identifier starting with a "*" followed by + // at most 10 characters. ISO 4217 exponents in the name are not supported, + // although the "fraction" is corresponds to an ISO 4217 exponent of 6. + currency: string; + + // unsigned 32 bit value in the currency, note that "1" here would + // correspond to 1 EUR or 1 USD, depending on `currency`, not 1 cent. + value: number; + + // unsigned 32 bit fractional value to be added to `value` representing + // an additional currency fraction, in units of one millionth (1e-6) + // of the base currency value. For example, a fraction + // of 500,000 would correspond to 50 cents. + fraction: number; + } + + +-------------- +Binary Formats +-------------- + + .. note:: + + Due to the way of handling `big` numbers by some platforms (such as + `JavaScript`, for example), wherever the following specification mentions + a 64-bit value, the actual implementations are strongly advised to rely on + arithmetic up to 53 bits. + + .. note:: + + Taler uses `libgnunetutil` for interfacing itself with the operating system, + doing crypto work, and other "low level" actions, therefore it is strongly + connected with the `GNUnet project `_. + +This section specifies the binary representation of messages used in Taler's +protocols. The message formats are given in a C-style pseudocode notation. +Padding is always specified explicitly, and numeric values are in network byte +order (big endian). + +Amounts +^^^^^^^ + +Amounts of currency are always expressed in terms of a base value, a fractional +value and the denomination of the currency: + +.. sourcecode:: c + + struct TALER_Amount { + uint64_t value; + uint32_t fraction; + uint8_t currency_code[12]; // i.e. "EUR" or "USD" + }; + struct TALER_AmountNBO { + uint64_t value; // in network byte order + uint32_t fraction; // in network byte order + uint8_t currency_code[12]; + }; + + +Time +^^^^ + +In signed messages, time is represented using 64-bit big-endian values, +denoting microseconds since the UNIX Epoch. `UINT64_MAX` represents "never". + +.. sourcecode:: c + + struct GNUNET_TIME_Absolute { + uint64_t timestamp_us; + }; + struct GNUNET_TIME_AbsoluteNBO { + uint64_t abs_value_us__; // in network byte order + }; + +Cryptographic primitives +^^^^^^^^^^^^^^^^^^^^^^^^ + +All elliptic curve operations are on Curve25519. Public and private keys are +thus 32 bytes, and signatures 64 bytes. For hashing, including HKDFs, Taler +uses 512-bit hash codes (64 bytes). + +.. sourcecode:: c + + struct GNUNET_HashCode { + uint8_t hash[64]; // usually SHA-512 + }; + +.. _reserve-pub: +.. sourcecode:: c + + struct TALER_ReservePublicKeyP { + uint8_t eddsa_pub[32]; + }; + +.. _reserve-priv: +.. sourcecode:: c + + struct TALER_ReservePrivateKeyP { + uint8_t eddsa_priv[32]; + }; + + struct TALER_ReserveSignatureP { + uint8_t eddsa_signature[64]; + }; + +.. _merchant-pub: +.. sourcecode:: c + + struct TALER_MerchantPublicKeyP { + uint8_t eddsa_pub[32]; + }; + + struct TALER_MerchantPrivateKeyP { + uint8_t eddsa_priv[32]; + }; + + struct TALER_TransferPublicKeyP { + uint8_t ecdhe_pub[32]; + }; + + struct TALER_TransferPrivateKeyP { + uint8_t ecdhe_priv[32]; + }; + +.. _sign-key-pub: +.. sourcecode:: c + + struct TALER_ExchangePublicKeyP { + uint8_t eddsa_pub[32]; + }; + +.. _sign-key-priv: +.. sourcecode:: c + + struct TALER_ExchangePrivateKeyP { + uint8_t eddsa_priv[32]; + }; + +.. _eddsa-sig: +.. sourcecode:: c + + struct TALER_ExchangeSignatureP { + uint8_t eddsa_signature[64]; + }; + + struct TALER_MasterPublicKeyP { + uint8_t eddsa_pub[32]; + }; + + struct TALER_MasterPrivateKeyP { + uint8_t eddsa_priv[32]; + }; + + struct TALER_MasterSignatureP { + uint8_t eddsa_signature[64]; + }; + +.. _eddsa-coin-pub: +.. sourcecode:: c + + union TALER_CoinSpendPublicKeyP { + uint8_t eddsa_pub[32]; + uint8_t ecdhe_pub[32]; + }; + +.. _coin-priv: +.. sourcecode:: c + + union TALER_CoinSpendPrivateKeyP { + uint8_t eddsa_priv[32]; + uint8_t ecdhe_priv[32]; + }; + + struct TALER_CoinSpendSignatureP { + uint8_t eddsa_signature[64]; + }; + + struct TALER_TransferSecretP { + uint8_t key[sizeof (struct GNUNET_HashCode)]; + }; + uint8_t key[sizeof (struct GNUNET_HashCode)]; + }; + + struct TALER_EncryptedLinkSecretP { + uint8_t enc[sizeof (struct TALER_LinkSecretP)]; + }; + +.. _Signatures: + +Signatures +^^^^^^^^^^ +Any piece of signed data, complies to the abstract data structure given below. + +.. sourcecode:: c + + struct Data { + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + type1_t payload1; + type2_t payload2; + ... + }; + + /*From gnunet_crypto_lib.h*/ + struct GNUNET_CRYPTO_EccSignaturePurpose { + /** + + The following constrains apply for a valid amount: + + * asd + * This field is used to express the context in + * which the signature is made, ensuring that a + * signature cannot be lifted from one part of the protocol + * to another. See `src/include/taler_signatures.h` within the + * exchange's codebase (git://taler.net/exchange) + */ + uint32_t purpose; + /** + * This field equals the number of bytes being signed, + * namely 'sizeof (struct Data)' + */ + uint32_t size; + }; + + +The following list contains all the data structure that can be signed in +Taler. Their definition is typically found in `src/include/taler_signatures.h`, +within the +`exchange's codebase `_. + +.. _TALER_WithdrawRequestPS: +.. sourcecode:: c + + struct TALER_WithdrawRequestPS { + /** + * purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct TALER_ReservePublicKeyP reserve_pub; + struct TALER_AmountNBO amount_with_fee; + struct TALER_AmountNBO withdraw_fee; + struct GNUNET_HashCode h_denomination_pub; + struct GNUNET_HashCode h_coin_envelope; + }; + +.. _TALER_DepositRequestPS: +.. sourcecode:: c + + struct TALER_DepositRequestPS { + /** + * purpose.purpose = TALER_SIGNATURE_WALLET_COIN_DEPOSIT + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode h_contract_terms; + struct GNUNET_HashCode h_wire; + struct GNUNET_TIME_AbsoluteNBO timestamp; + struct GNUNET_TIME_AbsoluteNBO refund_deadline; + struct TALER_AmountNBO amount_with_fee; + struct TALER_AmountNBO deposit_fee; + struct TALER_MerchantPublicKeyP merchant; + union TALER_CoinSpendPublicKeyP coin_pub; + }; + +.. _TALER_DepositConfirmationPS: +.. sourcecode:: c + + struct TALER_DepositConfirmationPS { + /** + * purpose.purpose = TALER_SIGNATURE_WALLET_CONFIRM_DEPOSIT + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode h_contract_terms; + struct GNUNET_HashCode h_wire; + struct GNUNET_TIME_AbsoluteNBO timestamp; + struct GNUNET_TIME_AbsoluteNBO refund_deadline; + struct TALER_AmountNBO amount_without_fee; + union TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_MerchantPublicKeyP merchant; + }; + +.. _TALER_RefreshMeltCoinAffirmationPS: +.. sourcecode:: c + + struct TALER_RefreshMeltCoinAffirmationPS { + /** + * purpose.purpose = TALER_SIGNATURE_WALLET_COIN_MELT + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode session_hash; + struct TALER_AmountNBO amount_with_fee; + struct TALER_AmountNBO melt_fee; + union TALER_CoinSpendPublicKeyP coin_pub; + }; + +.. _TALER_RefreshMeltConfirmationPS: +.. sourcecode:: c + + struct TALER_RefreshMeltConfirmationPS { + /** + * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode session_hash; + uint16_t noreveal_index; + }; + +.. _TALER_ExchangeSigningKeyValidityPS: +.. sourcecode:: c + + struct TALER_ExchangeSigningKeyValidityPS { + /** + * purpose.purpose = TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct TALER_MasterPublicKeyP master_public_key; + struct GNUNET_TIME_AbsoluteNBO start; + struct GNUNET_TIME_AbsoluteNBO expire; + struct GNUNET_TIME_AbsoluteNBO end; + struct TALER_ExchangePublicKeyP signkey_pub; + }; + + struct TALER_ExchangeKeySetPS { + /** + * purpose.purpose = TALER_SIGNATURE_EXCHANGE_KEY_SET + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_TIME_AbsoluteNBO list_issue_date; + struct GNUNET_HashCode hc; + }; + +.. _TALER_DenominationKeyValidityPS: +.. sourcecode:: c + + struct TALER_DenominationKeyValidityPS { + /** + * purpose.purpose = TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct TALER_MasterPublicKeyP master; + struct GNUNET_TIME_AbsoluteNBO start; + struct GNUNET_TIME_AbsoluteNBO expire_withdraw; + struct GNUNET_TIME_AbsoluteNBO expire_spend; + struct GNUNET_TIME_AbsoluteNBO expire_legal; + struct TALER_AmountNBO value; + struct TALER_AmountNBO fee_withdraw; + struct TALER_AmountNBO fee_deposit; + struct TALER_AmountNBO fee_refresh; + struct GNUNET_HashCode denom_hash; + }; + +.. _TALER_MasterWireDetailsPS: +.. sourcecode:: c + + struct TALER_MasterWireDetailsPS { + /** + * purpose.purpose = TALER_SIGNATURE_MASTER_WIRE_DETAILS + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode h_wire_details; + }; + + +.. _TALER_MasterWireFeePS: +.. sourcecode:: c + + struct TALER_MasterWireFeePS { + /** + * purpose.purpose = TALER_SIGNATURE_MASTER_WIRE_FEES + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode h_wire_method; + struct GNUNET_TIME_AbsoluteNBO start_date; + struct GNUNET_TIME_AbsoluteNBO end_date; + struct TALER_AmountNBO wire_fee; + struct TALER_AmountNBO closing_fee; + }; + +.. _TALER_DepositTrackPS: +.. sourcecode:: c + + struct TALER_DepositTrackPS { + /** + * purpose.purpose = TALER_SIGNATURE_MASTER_SEPA_DETAILS || TALER_SIGNATURE_MASTER_TEST_DETAILS + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode h_contract_terms; + struct GNUNET_HashCode h_wire; + struct TALER_MerchantPublicKeyP merchant; + struct TALER_CoinSpendPublicKeyP coin_pub; + }; + +.. _TALER_WireDepositDetailP: +.. sourcecode:: c + + struct TALER_WireDepositDetailP { + struct GNUNET_HashCode h_contract_terms; + struct GNUNET_TIME_AbsoluteNBO execution_time; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_AmountNBO deposit_value; + struct TALER_AmountNBO deposit_fee; + }; + + +.. _TALER_WireDepositDataPS: +.. sourcecode:: c + + struct TALER_WireDepositDataPS { + /** + * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct TALER_AmountNBO total; + struct TALER_AmountNBO wire_fee; + struct TALER_MerchantPublicKeyP merchant_pub; + struct GNUNET_HashCode h_wire; + struct GNUNET_HashCode h_details; + }; + +.. _TALER_ExchangeKeyValidityPS: +.. sourcecode:: c + + struct TALER_ExchangeKeyValidityPS { + /** + * purpose.purpose = TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode auditor_url_hash; + struct TALER_MasterPublicKeyP master; + struct GNUNET_TIME_AbsoluteNBO start; + struct GNUNET_TIME_AbsoluteNBO expire_withdraw; + struct GNUNET_TIME_AbsoluteNBO expire_spend; + struct GNUNET_TIME_AbsoluteNBO expire_legal; + struct TALER_AmountNBO value; + struct TALER_AmountNBO fee_withdraw; + struct TALER_AmountNBO fee_deposit; + struct TALER_AmountNBO fee_refresh; + struct GNUNET_HashCode denom_hash; + }; + +.. _TALER_PaymentResponsePS: +.. sourcecode:: c + + struct PaymentResponsePS { + /** + * purpose.purpose = TALER_SIGNATURE_MERCHANT_PAYMENT_OK + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode h_contract_terms; + }; + +.. _TALER_ContractPS: +.. sourcecode:: c + + struct TALER_ContractPS { + /** + * purpose.purpose = TALER_SIGNATURE_MERCHANT_CONTRACT + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct TALER_AmountNBO total_amount; + struct TALER_AmountNBO max_fee; + struct GNUNET_HashCode h_contract_terms; + struct TALER_MerchantPublicKeyP merchant_pub; + }; + +.. _TALER_ConfirmWirePS: +.. sourcecode:: c + + struct TALER_ConfirmWirePS { + /** + * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode h_wire; + struct GNUNET_HashCode h_contract_terms; + struct TALER_WireTransferIdentifierRawP wtid; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct GNUNET_TIME_AbsoluteNBO execution_time; + struct TALER_AmountNBO coin_contribution; + }; + +.. _TALER_RefundRequestPS: +.. sourcecode:: c + + struct TALER_RefundRequestPS { + /** + * purpose.purpose = TALER_SIGNATURE_MERCHANT_REFUND + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode h_contract_terms; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_MerchantPublicKeyP merchant; + uint64_t rtransaction_id; + struct TALER_AmountNBO refund_amount; + struct TALER_AmountNBO refund_fee; + }; + + struct TALER_MerchantRefundConfirmationPS { + /** + * purpose.purpose = TALER_SIGNATURE_MERCHANT_REFUND_OK + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + /** + * Hash of the order ID (a string), hashed without the 0-termination. + */ + struct GNUNET_HashCode h_order_id; + }; + + +.. _TALER_PaybackRequestPS: +.. sourcecode:: c + + struct TALER_PaybackRequestPS { + /** + * purpose.purpose = TALER_SIGNATURE_WALLET_COIN_PAYBACK + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct GNUNET_HashCode h_denom_pub; + struct TALER_DenominationBlindingKeyP coin_blind; + }; + + +.. _TALER_PaybackConfirmationPS: +.. sourcecode:: c + + struct TALER_PaybackConfirmationPS { + /** + * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_TIME_AbsoluteNBO timestamp; + struct TALER_AmountNBO payback_amount; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_ReservePublicKeyP reserve_pub; + }; + + +.. _TALER_ReserveCloseConfirmationPS: +.. sourcecode:: c + + struct TALER_ReserveCloseConfirmationPS { + /** + * purpose.purpose = TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_TIME_AbsoluteNBO timestamp; + struct TALER_AmountNBO closing_amount; + struct TALER_ReservePublicKeyP reserve_pub; + struct GNUNET_HashCode h_wire; + }; + +.. _TALER_CoinLinkSignaturePS: +.. sourcecode:: c + + struct TALER_CoinLinkSignaturePS { + /** + * purpose.purpose = TALER_SIGNATURE_WALLET_COIN_LINK + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode h_denom_pub; + struct TALER_CoinSpendPublicKeyP old_coin_pub; + struct TALER_TransferPublicKeyP transfer_pub; + struct GNUNET_HashCode coin_envelope_hash; + }; diff --git a/core/api-error.rst b/core/api-error.rst new file mode 100644 index 00000000..61716b72 --- /dev/null +++ b/core/api-error.rst @@ -0,0 +1,1204 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016 GNUnet e.V. and INRIA + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU 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 Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING. If not, see + + @author Marcello Stanisci + +.. + The reason to have a dedicate page for error codes was due to a buggy + behaviour in pages cross-linking: was not possible from other pages to + reference the '_error-codes' label (see just below) if we kept in api-common.rst + (which is the best place to place this error codes list). + +----------- +Error Codes +----------- + +The following list shows error codes defined in +`/src/include/taler_error_codes.h `_ + +.. _error-codes: +.. code-block:: c + + /** + * Enumeration with all possible Taler error codes. + */ + enum TALER_ErrorCode { + + /** + * Special code to indicate no error (or no "code" present). + */ + TALER_EC_NONE = 0, + + /** + * Special code to indicate that a non-integer error code was + * returned in the JSON response. + */ + TALER_EC_INVALID = 1, + + /** + * The response we got from the server was not even in JSON format. + */ + TALER_EC_INVALID_RESPONSE = 2, + + /** + * Generic implementation error: this function was not yet implemented. + */ + TALER_EC_NOT_IMPLEMENTED = 3, + + /* ********** generic error codes ************* */ + + /** + * The exchange failed to even just initialize its connection to the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DB_SETUP_FAILED = 1001, + + /** + * The exchange encountered an error event to just start + * the database transaction. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DB_START_FAILED = 1002, + + /** + * The exchange encountered an error event to commit + * the database transaction (hard, unrecoverable error). + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DB_COMMIT_FAILED_HARD = 1003, + + /** + * The exchange encountered an error event to commit + * the database transaction, even after repeatedly + * retrying it there was always a conflicting transaction. + * (This indicates a repeated serialization error; should + * only happen if some client maliciously tries to create + * conflicting concurrent transactions.) + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DB_COMMIT_FAILED_ON_RETRY = 1004, + + /** + * The exchange had insufficient memory to parse the request. This + * response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_PARSER_OUT_OF_MEMORY = 1005, + + /** + * The JSON in the client's request to the exchange was malformed. + * (Generic parse error). + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_JSON_INVALID = 1006, + + /** + * The JSON in the client's request to the exchange was malformed. + * Details about the location of the parse error are provided. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_JSON_INVALID_WITH_DETAILS = 1007, + + /** + * A required parameter in the request to the exchange was missing. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PARAMETER_MISSING = 1008, + + /** + * A parameter in the request to the exchange was malformed. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PARAMETER_MALFORMED = 1009, + + /* ********** request-specific error codes ************* */ + + /** + * The given reserve does not have sufficient funds to admit the + * requested withdraw operation at this time. The response includes + * the current "balance" of the reserve as well as the transaction + * "history" that lead to this balance. This response is provided + * with HTTP status code MHD_HTTP_FORBIDDEN. + */ + TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS = 1100, + + /** + * The exchange has no information about the "reserve_pub" that + * was given. + * This response is provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_WITHDRAW_RESERVE_UNKNOWN = 1101, + + /** + * The amount to withdraw together with the fee exceeds the + * numeric range for Taler amounts. This is not a client + * failure, as the coin value and fees come from the exchange's + * configuration. + * This response is provided with HTTP status code MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW = 1102, + + /** + * All of the deposited amounts into this reserve total up to a + * value that is too big for the numeric range for Taler amounts. + * This is not a client failure, as the transaction history comes + * from the exchange's configuration. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_AMOUNT_DEPOSITS_OVERFLOW = 1103, + + /** + * For one of the historic withdrawals from this reserve, the + * exchange could not find the denomination key. + * This is not a client failure, as the transaction history comes + * from the exchange's configuration. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_HISTORIC_DENOMINATION_KEY_NOT_FOUND = 1104, + + /** + * All of the withdrawals from reserve total up to a + * value that is too big for the numeric range for Taler amounts. + * This is not a client failure, as the transaction history comes + * from the exchange's configuration. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_AMOUNT_WITHDRAWALS_OVERFLOW = 1105, + + /** + * The exchange somehow knows about this reserve, but there seem to + * have been no wire transfers made. This is not a client failure, + * as this is a database consistency issue of the exchange. This + * response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_RESERVE_WITHOUT_WIRE_TRANSFER = 1106, + + /** + * The exchange failed to create the signature using the + * denomination key. This response is provided with HTTP status + * code MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_SIGNATURE_FAILED = 1107, + + /** + * The exchange failed to store the withdraw operation in its + * database. This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_DB_STORE_ERROR = 1108, + + /** + * The exchange failed to check against historic withdraw data from + * database (as part of ensuring the idempotency of the operation). + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_WITHDRAW_DB_FETCH_ERROR = 1109, + + /** + * The exchange is not aware of the denomination key + * the wallet requested for the withdrawal. + * This response is provided + * with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_WITHDRAW_DENOMINATION_KEY_NOT_FOUND = 1110, + + /** + * The signature of the reserve is not valid. This response is + * provided with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_WITHDRAW_RESERVE_SIGNATURE_INVALID = 1111, + + /** + * The exchange failed to obtain the transaction history of the + * given reserve from the database while generating an insufficient + * funds errors. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1112, + + /** + * When computing the reserve history, we ended up with a negative + * overall balance, which should be impossible. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_WITHDRAW_RESERVE_HISTORY_IMPOSSIBLE = 1113, + + /** + * The exchange failed to obtain the transaction history of the + * given reserve from the database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_RESERVE_STATUS_DB_ERROR = 1150, + + + /** + * The respective coin did not have sufficient residual value + * for the /deposit operation (i.e. due to double spending). + * The "history" in the respose provides the transaction history + * of the coin proving this fact. This response is provided + * with HTTP status code MHD_HTTP_FORBIDDEN. + */ + TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS = 1200, + + /** + * The exchange failed to obtain the transaction history of the + * given coin from the database (this does not happen merely because + * the coin is seen by the exchange for the first time). + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DEPOSIT_HISTORY_DB_ERROR = 1201, + + /** + * The exchange failed to store the /depost information in the + * database. This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DEPOSIT_STORE_DB_ERROR = 1202, + + /** + * The exchange database is unaware of the denomination key that + * signed the coin (however, the exchange process is; this is not + * supposed to happen; it can happen if someone decides to purge the + * DB behind the back of the exchange process). Hence the deposit + * is being refused. This response is provided with HTTP status + * code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DEPOSIT_DB_DENOMINATION_KEY_UNKNOWN = 1203, + + /** + * The exchange database is unaware of the denomination key that + * signed the coin (however, the exchange process is; this is not + * supposed to happen; it can happen if someone decides to purge the + * DB behind the back of the exchange process). Hence the deposit + * is being refused. This response is provided with HTTP status + * code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_DEPOSIT_DENOMINATION_KEY_UNKNOWN = 1204, + + /** + * The signature of the coin is not valid. This response is + * provided with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID = 1205, + + /** + * The signature of the denomination key over the coin is not valid. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_DENOMINATION_SIGNATURE_INVALID = 1206, + + /** + * The stated value of the coin after the deposit fee is subtracted + * would be negative. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE = 1207, + + /** + * The stated refund deadline is after the wire deadline. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE = 1208, + + /** + * The exchange does not recognize the validity of or support the + * given wire format type. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE = 1209, + + /** + * The exchange failed to canonicalize and hash the given wire format. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON = 1210, + + /** + * The hash of the given wire address does not match the hash + * specified in the contract. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT = 1211, + + /** + * The exchange failed to obtain the transaction history of the + * given coin from the database while generating an insufficient + * funds errors. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_DEPOSIT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1212, + + /** + * The exchange detected that the given account number + * is invalid for the selected wire format type. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_ACCOUNT_NUMBER = 1213, + + /** + * The signature over the given wire details is invalid. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE = 1214, + + /** + * The bank specified in the wire transfer format is not supported + * by this exchange. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_BANK = 1215, + + /** + * No wire format type was specified in the JSON wire format + * details. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_MISSING = 1216, + + /** + * The given wire format type is not supported by this + * exchange. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_UNSUPPORTED = 1217, + + + /** + * The respective coin did not have sufficient residual value + * for the /refresh/melt operation. The "history" in this + * response provdes the "residual_value" of the coin, which may + * be less than its "original_value". This response is provided + * with HTTP status code MHD_HTTP_FORBIDDEN. + */ + TALER_EC_REFRESH_MELT_INSUFFICIENT_FUNDS = 1300, + + /** + * The exchange is unaware of the denomination key that was + * used to sign the melted coin. This response is provided + * with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_REFRESH_MELT_DENOMINATION_KEY_NOT_FOUND = 1301, + + /** + * The exchange had an internal error reconstructing the + * transaction history of the coin that was being melted. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFRESH_MELT_COIN_HISTORY_COMPUTATION_FAILED = 1302, + + /** + * The exchange failed to check against historic melt data from + * database (as part of ensuring the idempotency of the operation). + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_MELT_DB_FETCH_ERROR = 1303, + + /** + * The exchange failed to store session data in the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR = 1304, + + /** + * The exchange failed to store refresh order data in the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_MELT_DB_STORE_ORDER_ERROR = 1305, + + /** + * The exchange failed to store commit data in the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_MELT_DB_STORE_COMMIT_ERROR = 1306, + + /** + * The exchange failed to store transfer keys in the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_MELT_DB_STORE_TRANSFER_ERROR = 1307, + + /** + * The exchange is unaware of the denomination key that was + * requested for one of the fresh coins. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_FRESH_DENOMINATION_KEY_NOT_FOUND = 1308, + + /** + * The exchange encountered a numeric overflow totaling up + * the cost for the refresh operation. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFRESH_MELT_COST_CALCULATION_OVERFLOW = 1309, + + /** + * During the transaction phase, the exchange could suddenly + * no longer find the denomination key that was + * used to sign the melted coin. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFRESH_MELT_DB_DENOMINATION_KEY_NOT_FOUND = 1310, + + /** + * The exchange encountered melt fees exceeding the melted + * coin's contribution. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION = 1311, + + /** + * The exchange's cost calculation does not add up to the + * melt fees specified in the request. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_FEES_MISSMATCH = 1312, + + /** + * The denomination key signature on the melted coin is invalid. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID = 1313, + + /** + * The exchange's cost calculation shows that the melt amount + * is below the costs of the transaction. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_AMOUNT_INSUFFICIENT = 1314, + + /** + * The signature made with the coin to be melted is invalid. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_COIN_SIGNATURE_INVALID = 1315, + + /** + * The size of the cut-and-choose dimension of the + * blinded coins request does not match #TALER_CNC_KAPPA. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_CNC_COIN_ARRAY_SIZE_INVALID = 1316, + + /** + * The size of the cut-and-choose dimension of the + * transfer keys request does not match #TALER_CNC_KAPPA. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_MELT_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1317, + + /** + * The exchange failed to obtain the transaction history of the + * given coin from the database while generating an insufficient + * funds errors. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFRESH_MELT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS = 1318, + + /** + * The provided transfer keys do not match up with the + * original commitment. Information about the original + * commitment is included in the response. This response is + * provided with HTTP status code MHD_HTTP_CONFLICT. + */ + TALER_EC_REFRESH_REVEAL_COMMITMENT_VIOLATION = 1350, + + /** + * Failed to blind the envelope to reconstruct the blinded + * coins for revealation checks. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_REVEAL_BLINDING_ERROR = 1351, + + /** + * Failed to produce the blinded signatures over the coins + * to be returned. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_REVEAL_SIGNING_ERROR = 1352, + + /** + * The exchange is unaware of the refresh sessino specified in + * the request. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN = 1353, + + /** + * The exchange failed to retrieve valid session data from the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR = 1354, + + /** + * The exchange failed to retrieve order data from the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR = 1355, + + /** + * The exchange failed to retrieve transfer keys from the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_REVEAL_DB_FETCH_TRANSFER_ERROR = 1356, + + /** + * The exchange failed to retrieve commitment data from the + * database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_ERROR. + */ + TALER_EC_REFRESH_REVEAL_DB_FETCH_COMMIT_ERROR = 1357, + + /** + * The size of the cut-and-choose dimension of the + * private transfer keys request does not match #TALER_CNC_KAPPA - 1. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFRESH_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID = 1358, + + + /** + * The coin specified in the link request is unknown to the exchange. + * This response is provided with HTTP status code + * MHD_HTTP_NOT_FOUND. + */ + TALER_EC_REFRESH_LINK_COIN_UNKNOWN = 1400, + + + /** + * The exchange knows literally nothing about the coin we were asked + * to refund. But without a transaction history, we cannot issue a + * refund. This is kind-of OK, the owner should just refresh it + * directly without executing the refund. This response is provided + * with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_REFUND_COIN_NOT_FOUND = 1500, + + /** + * We could not process the refund request as the coin's transaction + * history does not permit the requested refund at this time. The + * "history" in the response proves this. This response is provided + * with HTTP status code MHD_HTTP_CONFLICT. + */ + TALER_EC_REFUND_CONFLICT = 1501, + + /** + * The exchange knows about the coin we were asked to refund, but + * not about the specific /deposit operation. Hence, we cannot + * issue a refund (as we do not know if this merchant public key is + * authorized to do a refund). This response is provided with HTTP + * status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_REFUND_DEPOSIT_NOT_FOUND = 1503, + + /** + * The currency specified for the refund is different from + * the currency of the coin. This response is provided with HTTP + * status code MHD_HTTP_PRECONDITION_FAILED. + */ + TALER_EC_REFUND_CURRENCY_MISSMATCH = 1504, + + /** + * When we tried to check if we already paid out the coin, the + * exchange's database suddenly disagreed with data it previously + * provided (internal inconsistency). + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFUND_DB_INCONSISTENT = 1505, + + /** + * The exchange can no longer refund the customer/coin as the + * money was already transferred (paid out) to the merchant. + * (It should be past the refund deadline.) + * This response is provided with HTTP status code + * MHD_HTTP_GONE. + */ + TALER_EC_REFUND_MERCHANT_ALREADY_PAID = 1506, + + /** + * The amount the exchange was asked to refund exceeds + * (with fees) the total amount of the deposit (including fees). + * This response is provided with HTTP status code + * MHD_HTTP_PRECONDITION_FAILED. + */ + TALER_EC_REFUND_INSUFFICIENT_FUNDS = 1507, + + /** + * The exchange failed to recover information about the + * denomination key of the refunded coin (even though it + * recognizes the key). Hence it could not check the fee + * strucutre. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFUND_DENOMINATION_KEY_NOT_FOUND = 1508, + + /** + * The refund fee specified for the request is lower than + * the refund fee charged by the exchange for the given + * denomination key of the refunded coin. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFUND_FEE_TOO_LOW = 1509, + + /** + * The exchange failed to store the refund information to + * its database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_REFUND_STORE_DB_ERROR = 1510, + + /** + * The refund fee is specified in a different currency + * than the refund amount. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH = 1511, + + /** + * The refunded amount is smaller than the refund fee, + * which would result in a negative refund. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFUND_FEE_ABOVE_AMOUNT = 1512, + + /** + * The signature of the merchant is invalid. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_REFUND_MERCHANT_SIGNATURE_INVALID = 1513, + + + /** + * The wire format specified in the "sender_account_details" + * is not understood or not supported by this exchange. + * Returned with an HTTP status code of MHD_HTTP_NOT_FOUND. + * (As we did not find an interpretation of the wire format.) + */ + TALER_EC_ADMIN_ADD_INCOMING_WIREFORMAT_UNSUPPORTED = 1600, + + /** + * The currency specified in the "amount" parameter is not + * supported by this exhange. Returned with an HTTP status + * code of MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_ADMIN_ADD_INCOMING_CURRENCY_UNSUPPORTED = 1601, + + /** + * The exchange failed to store information about the incoming + * transfer in its database. This response is provided with HTTP + * status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_ADMIN_ADD_INCOMING_DB_STORE = 1602, + + /** + * The exchange encountered an error (that is not about not finding + * the wire transfer) trying to lookup a wire transfer identifier + * in the database. This response is provided with HTTP + * status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_DB_FETCH_FAILED = 1700, + + /** + * The exchange found internally inconsistent data when resolving a + * wire transfer identifier in the database. This response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_DB_INCONSISTENT = 1701, + + /** + * The exchange did not find information about the specified + * wire transfer identifier in the database. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND = 1702, + + + /** + * The exchange found internally inconsistent fee data when + * resolving a transaction in the database. This + * response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSACTION_DB_FEE_INCONSISTENT = 1800, + + /** + * The exchange encountered an error (that is not about not finding + * the transaction) trying to lookup a transaction + * in the database. This response is provided with HTTP + * status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSACTION_DB_FETCH_FAILED = 1801, + + /** + * The exchange did not find information about the specified + * transaction in the database. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_TRACK_TRANSACTION_NOT_FOUND = 1802, + + /** + * The exchange failed to identify the wire transfer of the + * transaction (or information about the plan that it was supposed + * to still happen in the future). This response is provided with + * HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSACTION_WTID_RESOLUTION_ERROR = 1803, + + /** + * The signature of the merchant is invalid. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_TRACK_TRANSACTION_MERCHANT_SIGNATURE_INVALID = 1804, + + + /* *********** Merchant backend error codes ********* */ + + /** + * The backend could not find the merchant instance specified + * in the request. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_CONTRACT_INSTANCE_UNKNOWN = 2000, + + /** + * The exchange failed to provide a meaningful response + * to a /deposit request. This response is provided + * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE. + */ + TALER_EC_PAY_EXCHANGE_FAILED = 2101, + + /** + * The merchant failed to commit the exchanges' response to + * a /deposit request to its database. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_PAY_DB_STORE_PAY_ERROR = 2102, + + /** + * The specified exchange is not supported/trusted by + * this merchant. This response is provided + * with HTTP status code MHD_HTTP_PRECONDITION_FAILED. + */ + TALER_EC_PAY_EXCHANGE_REJECTED = 2103, + + /** + * The denomination key used for payment is not listed among the + * denomination keys of the exchange. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_DENOMINATION_KEY_NOT_FOUND = 2104, + + /** + * The denomination key used for payment is not audited by an + * auditor approved by the merchant. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_DENOMINATION_KEY_AUDITOR_FAILURE = 2105, + + /** + * There was an integer overflow totaling up the amounts or + * deposit fees in the payment. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_AMOUNT_OVERFLOW = 2106, + + /** + * The deposit fees exceed the total value of the payment. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_FEES_EXCEED_PAYMENT = 2107, + + /** + * After considering deposit fees, the payment is insufficient + * to satisfy the required amount for the contract. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_PAYMENT_INSUFFICIENT_DUE_TO_FEES = 2108, + + /** + * While the merchant is happy to cover all applicable deposit fees, + * the payment is insufficient to satisfy the required amount for + * the contract. This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_PAYMENT_INSUFFICIENT = 2109, + + /** + * The signature over the contract of one of the coins + * was invalid. This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_COIN_SIGNATURE_INVALID = 2110, + + /** + * We failed to contact the exchange for the /pay request. + * This response is provided + * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE. + */ + TALER_EC_PAY_EXCHANGE_TIMEOUT = 2111, + + /** + * The backend could not find the merchant instance specified + * in the request. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_PAY_INSTANCE_UNKNOWN = 2112, + + /** + * The signature over the contract of the merchant + * was invalid. This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_MERCHANT_SIGNATURE_INVALID = 2113, + + /** + * The refund deadline was after the transfer deadline. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE = 2114, + + /** + * The request fails to provide coins for the payment. + * This response is provided with HTTP status code + * MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_COINS_ARRAY_EMPTY = 2115, + + /** + * The merchant failed to fetch the merchant's previous state with + * respect to a /pay request from its database. This response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_PAY_DB_FETCH_PAY_ERROR = 2116, + + /** + * The merchant failed to fetch the merchant's previous state with + * respect to transactions from its database. This response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR = 2117, + + /** + * The transaction ID was used for a conflicing transaction before. + * This response is + * provided with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_DB_TRANSACTION_ID_CONFLICT = 2118, + + /** + * The merchant failed to store the merchant's state with + * respect to the transaction in its database. This response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR = 2119, + + /** + * The exchange failed to provide a valid response to + * the merchant's /keys request. + * This response is provided + * with HTTP status code MHD_HTTP_SERVICE_UNAVAILABLE. + */ + TALER_EC_PAY_EXCHANGE_KEYS_FAILURE = 2120, + + /** + * The payment is too late, the offer has expired. + * This response is + * provided with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_PAY_OFFER_EXPIRED = 2121, + + + /** + * Integer overflow with sepcified timestamp argument detected. + * This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_HISTORY_TIMESTAMP_OVERFLOW = 2200, + + /** + * Failed to retrieve history from merchant database. + * This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_HISTORY_DB_FETCH_ERROR = 2201, + + /** + * We failed to contact the exchange for the /track/transaction + * request. This response is provided with HTTP status code + * MHD_HTTP_SERVICE_UNAVAILABLE. + */ + TALER_EC_TRACK_TRANSACTION_EXCHANGE_TIMEOUT = 2300, + + /** + * The backend could not find the merchant instance specified + * in the request. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_TRACK_TRANSACTION_INSTANCE_UNKNOWN = 2301, + + /** + * The backend could not find the transaction specified + * in the request. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_TRACK_TRANSACTION_TRANSACTION_UNKNOWN = 2302, + + /** + * The backend had a database access error trying to + * retrieve transaction data from its database. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSACTION_DB_FETCH_TRANSACTION_ERROR = 2303, + + /** + * The backend had a database access error trying to + * retrieve payment data from its database. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSACTION_DB_FETCH_PAYMENT_ERROR = 2304, + + /** + * The backend found no applicable deposits in the database. + * This is odd, as we know about the transaction, but not + * about deposits we made for the transaction. The response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_TRACK_TRANSACTION_DB_NO_DEPOSITS_ERROR = 2305, + + /** + * We failed to obtain a wire transfer identifier for one + * of the coins in the transaction. The response is + * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY if + * the exchange had a hard error, or MHD_HTTP_ACCEPTED if the + * exchange signaled that the transfer was in progress. + */ + TALER_EC_TRACK_TRANSACTION_COIN_TRACE_ERROR = 2306, + + /** + * We failed to obtain the full wire transfer identifier for the + * transfer one of the coins was aggregated into. + * The response is + * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY. + */ + TALER_EC_TRACK_TRANSACTION_WIRE_TRANSFER_TRACE_ERROR = 2307, + + /** + * We got conflicting reports from the exhange with + * respect to which transfers are included in which + * aggregate. + * The response is + * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY. + */ + TALER_EC_TRACK_TRANSACTION_CONFLICTING_REPORTS = 2308, + + + /** + * We failed to contact the exchange for the /track/transfer + * request. This response is provided with HTTP status code + * MHD_HTTP_SERVICE_UNAVAILABLE. + */ + TALER_EC_TRACK_TRANSFER_EXCHANGE_TIMEOUT = 2400, + + /** + * The backend could not find the merchant instance specified + * in the request. This response is + * provided with HTTP status code MHD_HTTP_NOT_FOUND. + */ + TALER_EC_TRACK_TRANSFER_INSTANCE_UNKNOWN = 2401, + + /** + * We failed to persist coin wire transfer information in + * our merchant database. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_DB_STORE_COIN_ERROR = 2402, + + /** + * We internally failed to execute the /track/transfer request. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_REQUEST_ERROR = 2403, + + /** + * We failed to persist wire transfer information in + * our merchant database. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_DB_STORE_TRANSFER_ERROR = 2404, + + /** + * The exchange returned an error from /track/transfer. + * The response is + * provided with HTTP status code MHD_HTTP_FAILED_DEPENDENCY. + */ + TALER_EC_TRACK_TRANSFER_EXCHANGE_ERROR = 2405, + + /** + * We failed to fetch deposit information from + * our merchant database. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_DB_FETCH_DEPOSIT_ERROR = 2406, + + /** + * We encountered an internal logic error. + * The response is + * provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_DB_INTERNAL_LOGIC_ERROR = 2407, + + /** + * The exchange gave conflicting information about a coin which has + * been wire transferred. + * The response is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TRACK_TRANSFER_CONFLICTING_REPORTS = 2408, + + /** + * The hash provided in the request of /map/in does not match + * the contract sent alongside in the same request. + */ + TALER_EC_MAP_IN_UNMATCHED_HASH = 2500, + + /** + * The backend encountered an error while trying to store the + * pair into the database. + * The response is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_MAP_IN_STORE_DB_ERROR = 2501, + + /** + * The backend encountered an error while trying to retrieve the + * contract from database. Likely to be an internal error. + */ + TALER_EC_MAP_OUT_GET_FROM_DB_ERROR = 2502, + + + /** + * The backend encountered an error while trying to retrieve the + * contract from database. Likely to be an internal error. + */ + TALER_EC_MAP_OUT_CONTRACT_UNKNOWN = 2503, + + /* ********** /test API error codes ************* */ + + /** + * The exchange failed to compute ECDH. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TEST_ECDH_ERROR = 4000, + + /** + * The EdDSA test signature is invalid. This response is provided + * with HTTP status code MHD_HTTP_BAD_REQUEST. + */ + TALER_EC_TEST_EDDSA_INVALID = 4001, + + /** + * The exchange failed to compute the EdDSA test signature. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TEST_EDDSA_ERROR = 4002, + + /** + * The exchange failed to generate an RSA key. This response is provided + * with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TEST_RSA_GEN_ERROR = 4003, + + /** + * The exchange failed to compute the public RSA key. This response + * is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TEST_RSA_PUB_ERROR = 4004, + + /** + * The exchange failed to compute the RSA signature. This response + * is provided with HTTP status code MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_TEST_RSA_SIGN_ERROR = 4005, + + + /** + * End of error code range. + */ + TALER_EC_END = 9999 + }; diff --git a/core/api-exchange.rst b/core/api-exchange.rst new file mode 100644 index 00000000..1d03dae9 --- /dev/null +++ b/core/api-exchange.rst @@ -0,0 +1,1546 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014-2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING. If not, see + + @author Christian Grothoff + +============================= +The Exchange RESTful JSON API +============================= + +The API specified here follows the :ref:`general conventions ` +for all details not specified in the individual requests. +The `glossary ` +defines all specific terms used in this section. + +.. _keys: + +----------------------- +Obtaining Exchange Keys +----------------------- + +This API is used by wallets and merchants to obtain global information about +the exchange, such as online signing keys, available denominations and the fee +structure. This is typically the first call any exchange client makes, as it +returns information required to process all of the other interactions with the +exchange. The returned information is secured by (1) signature(s) from the exchange, +especially the long-term offline signing key of the exchange, which clients should +cache; (2) signature(s) from auditors, and the auditor keys should be +hard-coded into the wallet as they are the trust anchors for Taler; (3) +possibly by using HTTPS. + + +.. http:get:: /keys + + Get a list of all denomination keys offered by the bank, + as well as the bank's current online signing key. + + **Request:** + + :query last_issue_date: optional argument specifying the maximum value of any of the "stamp_start" members of the denomination keys of a "/keys" response that is already known to the client. Allows the exchange to only return keys that have changed since that timestamp. The given value must be an unsigned 64-bit integer representing seconds after 1970. If the timestamp does not exactly match the "stamp_start" of one of the denomination keys, all keys are returned. + + **Response:** + + :status 200 OK: + The exchange responds with a `ExchangeKeysResponse`_ object. This request should + virtually always be successful. + + **Details:** + + .. _ExchangeKeysResponse: + .. code-block:: tsref + + interface ExchangeKeysResponse { + // libtool-style representation of the Taler protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: String; + + // EdDSA master public key of the exchange, used to sign entries in `denoms` and `signkeys` + master_public_key: EddsaPublicKey; + + // Relative duration until inactive reserves are closed; not signed, expressed as + // a string in relative time in microseconds, i.e. "/Delay(1000)/" for 1 second. + reserve_closing_delay: RelativeTime; + + // Denominations offered by this exchange. + denoms: Denom[]; + + // Denominations for which the exchange currently offers/requests payback. + payback: Payback[]; + + // The date when the denomination keys were last updated. + list_issue_date: Timestamp; + + // Auditors of the exchange. + auditors: Auditor[]; + + // The exchange's signing keys. + signkeys: SignKey[]; + + // compact EdDSA `signature`_ (binary-only) over the SHA-512 hash of the + // concatenation of all SHA-512 hashes of the RSA denomination public keys + // in `denoms` in the same order as they were in `denoms`. Note that for + // hashing, the binary format of the RSA public keys is used, and not their + // `base32 encoding `_. Wallets cannot do much with this signature by itself; + // it is only useful when multiple clients need to establish that the exchange + // is sabotaging end-user anonymity by giving disjoint denomination keys to + // different users. If a exchange were to do this, this signature allows the + // clients to demonstrate to the public that the exchange is dishonest. + eddsa_sig: EddsaSignature; + + // Public EdDSA key of the exchange that was used to generate the signature. + // Should match one of the exchange's signing keys from /keys. It is given + // explicitly as the client might otherwise be confused by clock skew as to + // which signing key was used. + eddsa_pub: EddsaPublicKey; + } + + .. _tsref-type-Denom: + .. code-block:: tsref + + interface Denom { + // How much are coins of this denomination worth? + value: Amount; + + // When does the denomination key become valid? + stamp_start: Timestamp; + + // When is it no longer possible to deposit coins + // of this denomination? + stamp_expire_withdraw: Timestamp; + + // Timestamp indicating by when legal disputes relating to these coins must + // be settled, as the exchange will afterwards destroy its evidence relating to + // transactions involving this coin. + stamp_expire_legal: Timestamp; + + // Public (RSA) key for the denomination. + denom_pub: RsaPublicKey; + + // Fee charged by the exchange for withdrawing a coin of this denomination + fee_withdraw: Amount; + + // Fee charged by the exchange for depositing a coin of this denomination + fee_deposit: Amount; + + // Fee charged by the exchange for refreshing a coin of this denomination + fee_refresh: Amount; + + // Fee charged by the exchange for refunding a coin of this denomination + fee_refund: Amount; + + // Signature of `TALER_DenominationKeyValidityPS`_ + master_sig: EddsaSignature; + } + + Fees for any of the operations can be zero, but the fields must still be + present. The currency of the `fee_deposit`, `fee_refresh` and `fee_refund` must match the + currency of the `value`. Theoretically, the `fee_withdraw` could be in a + different currency, but this is not currently supported by the + implementation. + + .. _tsref-type-Payback: + .. code-block:: tsref + + interface Payback { + // hash of the public key of the denomination that is being revoked under + // emergency protocol (see /payback). + h_denom_pub: HashCode; + + // We do not include any signature here, as the primary use-case for + // this emergency involves the exchange having lost its signing keys, + // so such a signature here would be pretty worthless. However, the + // exchange will not honor /payback requests unless they are for + // denomination keys listed here. + } + + A signing key in the `signkeys` list is a JSON object with the following fields: + + .. _tsref-type-SignKey: + .. code-block:: tsref + + interface SignKey { + // The actual exchange's EdDSA signing public key. + key: EddsaPublicKey; + + // Initial validity date for the signing key. + stamp_start: Timestamp; + + // Date when the exchange will stop using the signing key, allowed to overlap + // slightly with the next signing key's validity to allow for clock skew. + stamp_expire: Timestamp; + + // Date when all signatures made by the signing key expire and should + // henceforth no longer be considered valid in legal disputes. + stamp_end: Timestamp; + + // Signature over `key` and `stamp_expire` by the exchange master key. + // Must have purpose TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY. + master_sig: EddsaSignature; + } + + An entry in the `auditors` list is a JSON object with the following fields: + + .. _tsref-type-Auditor: + .. code-block:: tsref + + interface Auditor { + // The auditor's EdDSA signing public key. + auditor_pub: EddsaPublicKey; + + // The auditor's URL. + auditor_url: string; + + // An array of denomination keys the auditor affirms with its signature. + // Note that the message only includes the hash of the public key, while the + // signature is actually over the expanded information including expiration + // times and fees. The exact format is described below. + denomination_keys: DenominationKey[]; + } + + .. _tsref-type-DenominationKey: + .. code-block:: tsref + + interface DenominationKey { + // hash of the public RSA key used to sign coins of the respective + // denomination. Note that the auditor's signature covers more than just + // the hash, but this other information is already provided in `denoms` and + // thus not repeated here. + denom_pub_h: HashCode; + + // Signature of `TALER_ExchangeKeyValidityPS`_ + auditor_sig: EddsaSignature; + } + + The same auditor may appear multiple times in the array for different subsets + of denomination keys, and the same denomination key hash may be listed + multiple times for the same or different auditors. The wallet or merchant + just should check that the denomination keys they use are in the set for at + least one of the auditors that they accept. + + .. note:: + + Both the individual denominations *and* the denomination list is signed, + allowing customers to prove that they received an inconsistent list. + +.. _wire-req: + +----------------------------------- +Obtaining wire-transfer information +----------------------------------- + +.. http:get:: /wire + + Returns a list of payment methods supported by the exchange. The idea is that wallets may use this information to instruct users on how to perform wire transfers to top up their wallets. + + **Response:** + + :status 200: The exchange responds with a `WireResponse`_ object. This request should virtually always be successful. + + **Details:** + + .. _WireResponse: + .. _tsref-type-WireResponse: + .. code-block:: tsref + + interface WireResponse { + + // Array of wire accounts operated by the exchange for + // incoming wire transfers. + accounts: WireAccount[]; + + // Object mapping names of wire methods (i.e. "sepa" or "x-taler-bank") + // to wire fees. + fees: { method : AggregateTransferFee }; + } + + The specification for the account object is: + + .. _WireAccouunt: + .. _tsref-type-WireAccount: + .. code-block:: tsref + + interface WireAccount { + // payto:// URL identifying the account and wire method + url: string; + + // Salt value (used when hashing 'url' to verify signature) + salt: string; + + // Signature using the exchange's offline key + // with purpose TALER_SIGNATURE_MASTER_WIRE_DETAILS. + master_sig: EddsaSignature; + } + + Aggregate wire transfer fees representing the fees the exchange + charges per wire transfer to a merchant must be specified as an + array in all wire transfer response objects under `fees`. The + respective array contains objects with the following members: + + .. _AggregateTransferFee: + .. _tsref-type-AggregateTransferFee: + .. code-block:: tsref + + interface AggregateTransferFee { + // Per transfer wire transfer fee. + wire_fee: Amount; + + // Per transfer closing fee. + closing_fee: Amount; + + // What date (inclusive) does this fee go into effect? + // The different fees must cover the full time period in which + // any of the denomination keys are valid without overlap. + start_date: Timestamp; + + // What date (exclusive) does this fee stop going into effect? + // The different fees must cover the full time period in which + // any of the denomination keys are valid without overlap. + end_date: Timestamp; + + // Signature of `TALER_MasterWireFeePS`_ with purpose TALER_SIGNATURE_MASTER_WIRE_FEES + sig: EddsaSignature; + } + +---------- +Withdrawal +---------- + +This API is used by the wallet to obtain digital coins. + +When transfering money to the exchange such as via SEPA transfers, the exchange creates +a *reserve*, which keeps the money from the customer. The customer must +specify an EdDSA reserve public key as part of the transfer, and can then +withdraw digital coins using the corresponding private key. All incoming and +outgoing transactions are recorded under the corresponding public key by the +exchange. + + .. note:: + + Eventually the exchange will need to advertise a policy for how long it will keep transaction histories for inactive or even fully drained reserves. We will therefore need some additional handler similar to `/keys` to advertise those terms of service. + + +.. http:get:: /reserve/status + + Request information about a reserve. + + .. note:: + The client currently does not have to demonstrate knowledge of the private + key of the reserve to make this request, which makes the reserve's public + key privileged information known only to the client, their bank, and the + exchange. In future, we might wish to revisit this decision to improve + security, such as by having the client EdDSA-sign an ECDHE key to be used + to derive a symmetric key to encrypt the response. This would be useful if + for example HTTPS were not used for communication with the exchange. + + **Request:** + + :query reserve_pub: EdDSA reserve public key identifying the reserve. + + **Response:** + + :status 200 OK: + The exchange responds with a `ReserveStatus`_ object; the reserve was known to the exchange, + :status 404 Not Found: The reserve key does not belong to a reserve known to the exchange. + + **Details:** + + .. _ReserveStatus: + .. code-block:: tsref + + interface ReserveStatus { + // Balance left in the reserve. + balance: Amount; + + // Transaction history for this reserve + history: TransactionHistoryItem[]; + } + + Objects in the transaction history have the following format: + + .. _tsref-type-TransactionHistoryItem: + .. code-block:: tsref + + interface TransactionHistoryItem { + // Either "WITHDRAW", "DEPOSIT", "PAYBACK", or "CLOSING" + type: string; + + // The amount that was withdrawn or deposited (incl. fee) + // or paid back, or the closing amount. + amount: Amount; + + // Hash of the denomination public key of the coin, if + // type is "WITHDRAW". + h_denom_pub?: base32; + + // Hash of the blinded coin to be signed, if + // type is "WITHDRAW". + h_coin_envelope?: base32; + + // Signature of `TALER_WithdrawRequestPS`_ created with the `reserves's private key `_. Only present if type is "WITHDRAW". + reserve_sig?: EddsaSignature; + + // The fee that was charged for "WITHDRAW". + withdraw_fee?: Amount; + + // The fee that was charged for "CLOSING". + closing_fee?: Amount; + + // Sender account payto://-URL, only present if type is "DEPOSIT". + sender_account_url?: String; + + // Receiver account details, only present if type is "PAYBACK". + receiver_account_details?: any; + + // Wire transfer identifier, only present if type is "PAYBACK". + wire_transfer?: any; + + // Transfer details uniquely identifying the transfer, only present if type is "DEPOSIT". + wire_reference?: any; + + // Wire transfer subject, only present if type is "CLOSING". + wtid?: any; + + // Hash of the wire account into which the funds were + // returned to, present if type is "CLOSING". + h_wire?: base32; + + // If `type` is "PAYBACK", this is a signature over a `struct TALER_PaybackConfirmationPS` with purpose TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK. + // If `type` is "CLOSING", this is a signature over a `struct TALER_ReserveCloseConfirmationPS` with purpose TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED. + // Not present for other values of `type`. + exchange_sig?: EddsaSignature; + + // Public key used to create `exchange_sig`, only present if `exchange_sig` is present. + exchange_pub?: EddsaPublicKey; + + // Public key of the coin that was paid back; only present if type is "PAYBACK". + coin_pub?: CoinPublicKey; + + // Timestamp when the exchange received the /payback or executed the wire transfer. Only present if `type` is "DEPOSIT", "PAYBACK" or "CLOSING". + timestamp?: Timestamp; + } + + +.. http:post:: /reserve/withdraw + + Withdraw a coin of the specified denomination. Note that the client should + commit all of the request details, including the private key of the coin and + the blinding factor, to disk *before* issuing this request, so that it can + recover the information if necessary in case of transient failures, like + power outage, network outage, etc. + + **Request:** The request body must be a `WithdrawRequest`_ object. + + **Response:** + + :status 200 OK: + The request was succesful, and the response is a `WithdrawResponse`. Note that repeating exactly the same request + will again yield the same response, so if the network goes down during the + transaction or before the client can commit the coin signature to disk, the + coin is not lost. + :status 401 Unauthorized: The signature is invalid. + :status 404 Not Found: + The denomination key or the reserve are not known to the exchange. If the + denomination key is unknown, this suggests a bug in the wallet as the + wallet should have used current denomination keys from `/keys`. If the + reserve is unknown, the wallet should not report a hard error yet, but + instead simply wait for up to a day, as the wire transaction might simply + not yet have completed and might be known to the exchange in the near future. + In this case, the wallet should repeat the exact same request later again + using exactly the same blinded coin. + :status 403 Forbidden: + The balance of the reserve is not sufficient to withdraw a coin of the indicated denomination. + The response is `WithdrawError`_ object. + + + **Details:** + + .. _WithdrawRequest: + .. code-block:: tsref + + interface WithdrawRequest { + // Hash of a denomination public key (RSA), specifying the type of coin the client + // would like the exchange to create. + denom_pub_hash: HashCode; + + // coin's blinded public key, should be (blindly) signed by the exchange's + // denomination private key + coin_ev: CoinEnvelope; + + // `public (EdDSA) key `_ of the reserve from which the coin should be + // withdrawn. The total amount deducted will be the coin's value plus the + // withdrawal fee as specified with the denomination information. + reserve_pub: EddsaPublicKey; + + // Signature of `TALER_WithdrawRequestPS`_ created with the `reserves's private key `_ + reserve_sig: EddsaSignature; + } + + + .. _WithdrawResponse: + .. code-block:: tsref + + interface WithdrawResponse { + // The blinded RSA signature over the `coin_ev`, affirms the coin's + // validity after unblinding. + ev_sig: BlindedRsaSignature; + } + + .. _WithdrawError: + .. code-block:: tsref + + interface WithdrawError { + // Constant "Insufficient funds" + error: string; + + // Amount left in the reserve + balance: Amount; + + // History of the reserve's activity, in the same format as returned by /reserve/status. + history: TransactionHistoryItem[] + } + +.. _deposit-par: + +------- +Deposit +------- + +Deposit operations are requested by a merchant during a transaction. For the +deposit operation, the merchant has to obtain the deposit permission for a coin +from their customer who owns the coin. When depositing a coin, the merchant is +credited an amount specified in the deposit permission, possibly a fraction of +the total coin's value, minus the deposit fee as specified by the coin's +denomination. + + +.. _deposit: + +.. http:POST:: /deposit + + Deposit the given coin and ask the exchange to transfer the given :ref:`amount` + to the merchants bank account. This API is used by the merchant to redeem + the digital coins. The request should contain a JSON object with the + following fields: + + **Request:** The request body must be a `DepositRequest`_ object. + + **Response:** + + :status 200 Ok: + The operation succeeded, the exchange confirms that no double-spending took place. The response will include a `DepositSuccess`_ object. + :status 401 Unauthorized: + One of the signatures is invalid. + :status 403 Forbidden: + The deposit operation has failed because the coin has insufficient + residual value; the request should not be repeated again with this coin. + In this case, the response is a `DepositDoubleSpendError`_. + :status 404 Not Found: + Either the denomination key is not recognized (expired or invalid) or + the wire type is not recognized. + + **Details:** + + .. _DepositRequest: + .. code-block:: tsref + + interface DepositRequest { + // Amount to be deposited, can be a fraction of the + // coin's total value. + f: Amount; + + // The merchant's account details. This must be a JSON object whose format + // must correspond to one of the supported wire transfer formats of the exchange. + // See `wireformats`_. + wire: Object; + + // SHA-512 hash of the merchant's payment details from `wire`. Although + // strictly speaking redundant, this helps detect inconsistencies. + // TODO: change to 'h_wire'. + H_wire: HashCode; + + // SHA-512 hash of the contact of the merchant with the customer. Further + // details are never disclosed to the exchange. + h_contract_terms: HashCode; + + // `coin's public key `_, both ECDHE and EdDSA. + coin_pub: CoinPublicKey; + + // Hash of denomination RSA key with which the coin is signed + denom_pub_hash: HashCode; + + // exchange's unblinded RSA signature of the coin + ub_sig: RsaSignature; + + // timestamp when the contract was finalized, must match approximately the + // current time of the exchange; if the timestamp is too far off, the + // exchange returns "400 Bad Request" with an error code of + // "TALER_EC_DEPOSIT_INVALID_TIMESTAMP". + timestamp: Timestamp; + + // indicative time by which the exchange undertakes to transfer the funds to + // the merchant, in case of successful payment. + wire_deadline: Timestamp; + + // EdDSA `public key of the merchant `_, so that the client can identify the + // merchant for refund requests. + merchant_pub: EddsaPublicKey; + + // date until which the merchant can issue a refund to the customer via the + // exchange, possibly zero if refunds are not allowed. + refund_deadline: Timestamp; + + // Signature of `TALER_DepositRequestPS`_, made by the customer with the `coin's private key `_ + coin_sig: EddsaSignature; + } + + The deposit operation succeeds if the coin is valid for making a deposit and + has enough residual value that has not already been deposited or melted. + + + .. _`tsref-type-DepositSuccess`: + .. _DepositSuccess: + .. code-block:: tsref + + interface DepositSuccess { + // The string constant "DEPOSIT_OK" + status: string; + + // the EdDSA signature of `TALER_DepositConfirmationPS`_ using a current + // `signing key of the exchange `_ affirming the successful + // deposit and that the exchange will transfer the funds after the refund + // deadline, or as soon as possible if the refund deadline is zero. + sig: EddsaSignature; + + // `public EdDSA key of the exchange `_ that was used to + // generate the signature. + // Should match one of the exchange's signing keys from /keys. It is given + // explicitly as the client might otherwise be confused by clock skew as to + // which signing key was used. + pub: EddsaPublicKey; + } + + .. _DepositDoubleSpendError: + .. code-block:: tsref + + interface DepositDoubleSpendError { + // The string constant "insufficient funds" + error: string; + + // Transaction history for the coin that is + // being double-spended + history: CoinSpendHistoryItem[]; + } + + .. _`tsref-type-CoinSpendHistoryItem`: + .. _CoinSpendHistoryItem: + .. code-block:: tsref + + interface CoinSpendHistoryItem { + // Either "DEPOSIT", "MELT", "REFUND", "PAYBACK", + // "OLD-COIN-PAYBACK" or "PAYBACK-REFRESH" + type: string; + + // The total amount of the coin's value absorbed (or restored in the case of a refund) by this transaction. + // Note that for deposit and melt this means the amount given includes + // the transaction fee, while for refunds the amount given excludes + // the transaction fee. The current coin value can thus be computed by + // subtracting deposit and melt amounts and adding refund amounts from + // the coin's denomination value. + amount: Amount; + + // Deposit fee in case of type "DEPOSIT". + deposit_fee: Amount; + + // public key of the merchant, for "DEPOSIT" operations. + merchant_pub?: EddsaPublicKey; + + // date when the operation was made. + // Only for "DEPOSIT", "PAYBACK", "OLD-COIN-PAYBACK" and + // "PAYBACK-REFRESH" operations. + timestamp?: Timestamp; + + // date until which the merchant can issue a refund to the customer via the + // exchange, possibly zero if refunds are not allowed. Only for "DEPOSIT" operations. + refund_deadline?: Timestamp; + + // Signature by the coin, only present if `type` is "DEPOSIT" or "MELT" + coin_sig?: EddsaSignature; + + // Deposit fee in case of type "MELT". + melt_fee: Amount; + + // Commitment from the melt operation, only for "MELT". + rc?: TALER_RefreshCommitmentP; + + // Hash of the bank account from where we received the funds, + // only present if `type` is "DEPOSIT" + h_wire?: HashCode; + + // Deposit fee in case of type "REFUND". + refund_fee?: Amount; + + // Hash over the proposal data of the contract that + // is being paid (if type is "DEPOSIT") or refunded (if + // `type` is "REFUND"); otherwise absent. + h_contract_terms?: HashCode; + + // Refund transaction ID. Only present if `type` is + // "REFUND" + rtransaction_id?: integer; + + // `EdDSA Signature `_ authorizing the REFUND. Made with + // the `public key of the merchant `_. + // Only present if `type` is "REFUND" + merchant_sig?: EddsaSignature; + + // public key of the reserve that will receive the funds, for "PAYBACK" operations. + reserve_pub?: EddsaPublicKey; + + // Signature by the exchange, only present if `type` is "PAYBACK", + // "OLD-COIN-PAYBACK" or "PAYBACK-REFRESH". Signature is + // of type TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK for "PAYBACK", + // and of type TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK_REFRESH otherwise. + exchange_sig?: EddsaSignature; + + // public key used to sign `exchange_sig`, only present if `exchange_sig` present. + exchange_pub?: EddsaPublicKey; + + // Blinding factor of the revoked new coin, + // only present if `type` is "REFRESH_PAYBACK". + new_coin_blinding_secret: RsaBlindingKeySecret; + + // Blinded public key of the revoked new coin, + // only present if `type` is "REFRESH_PAYBACK". + new_coin_ev: RsaBlindingKeySecret; + } + +---------- +Refreshing +---------- + +Refreshing creates `n` new coins from `m` old coins, where the sum of +denominations of the new coins must be smaller than the sum of the old coins' +denominations plus melting (refresh) and withdrawal fees charged by the exchange. +The refreshing API can be used by wallets to melt partially spent coins, making +transactions with the freshly exchangeed coins unlinkabe to previous transactions +by anyone except the wallet itself. + +However, the new coins are linkable from the private keys of all old coins +using the /refresh/link request. While /refresh/link must be implemented by +the exchange to achieve taxability, wallets do not really ever need that part of +the API during normal operation. + +.. _refresh: +.. http:post:: /refresh/melt + + "Melts" coins. Invalidates the coins and prepares for exchangeing of fresh + coins. Taler uses a global parameter `kappa` for the cut-and-choose + component of the protocol, for which this request is the commitment. Thus, + various arguments are given `kappa`-times in this step. At present `kappa` + is always 3. + + + :status 401 Unauthorized: + One of the signatures is invalid. + :status 200 OK: + The request was succesful. The response body is `MeltResponse`_ in this case. + :status 403 Forbidden: + The operation is not allowed as at least one of the coins has insufficient funds. The response + is `MeltForbiddenResponse`_ in this case. + :status 404: + the exchange does not recognize the denomination key as belonging to the exchange, + or it has expired + + **Details:** + + + .. code-block:: tsref + + interface MeltRequest { + + // `Coin public key `_, uniquely identifies the coin to be melted + coin_pub: string; + + // Hash of the denomination public key, to determine total coin value. + denom_pub_hash: HashCode; + + // Signature over the `coin public key `_ by the denomination. + denom_sig: RsaSignature; + + // Signature by the `coin `_ over the melt commitment. + confirm_sig: EddsaSignature; + + // Amount of the value of the coin that should be melted as part of + // this refresh operation, including melting fee. + value_with_fee: Amount; + + // Melt commitment. Hash over the various coins to be withdrawn. + // See also `TALER_refresh_get_commitment()` + rc: TALER_RefreshCommitmentP; + + } + + For details about the HKDF used to derive the new coin private keys and + the blinding factors from ECDHE between the transfer public keys and + the private key of the melted coin, please refer to the + implementation in `libtalerutil`. + + .. _tsref-type-MeltResponse: + .. _MeltResponse: + .. code-block:: tsref + + interface MeltResponse { + // Which of the `kappa` indices does the client not have to reveal. + noreveal_index: number; + + // Signature of `TALER_RefreshMeltConfirmationPS`_ whereby the exchange + // affirms the successful melt and confirming the `noreveal_index` + exchange_sig: EddsaSignature; + + // `public EdDSA key `_ of the exchange that was used to generate the signature. + // Should match one of the exchange's signing keys from /keys. Again given + // explicitly as the client might otherwise be confused by clock skew as to + // which signing key was used. + exchange_pub: EddsaPublicKey; + } + + + .. _tsref-type-MeltForbiddenResponse: + .. _MeltForbiddenResponse: + .. code-block:: tsref + + interface MeltForbiddenResponse { + // Always "insufficient funds" + error: string; + + // public key of a melted coin that had insufficient funds + coin_pub: EddsaPublicKey; + + // original total value of the coin + original_value: Amount; + + // remaining value of the coin + residual_value: Amount; + + // amount of the coin's value that was to be melted + requested_value: Amount; + + // The transaction list of the respective coin that failed to have sufficient funds left. + // Note that only the transaction history for one bogus coin is given, + // even if multiple coins would have failed the check. + history: CoinSpendHistoryItem[]; + } + + +.. http:post:: /refresh/reveal + + Reveal previously commited values to the exchange, except for the values + corresponding to the `noreveal_index` returned by the /exchange/melt step. + + Errors such as failing to do proper arithmetic when it comes to calculating + the total of the coin values and fees are simply reported as bad requests. + This includes issues such as melting the same coin twice in the same session, + which is simply not allowed. However, theoretically it is possible to melt a + coin twice, as long as the `value_with_fee` of the two melting operations is + not larger than the total remaining value of the coin before the melting + operations. Nevertheless, this is not really useful. + + :status 200 OK: + The transfer private keys matched the commitment and the original request was well-formed. + The response body is a `RevealResponse`_ + :status 409 Conflict: + There is a problem between the original commitment and the revealed private + keys. The returned information is proof of the missmatch, and therefore + rather verbose, as it includes most of the original /refresh/melt request, + but of course expected to be primarily used for diagnostics. + The response body is a `RevealConflictResponse`_. + + **Details:** + + Request body contains a JSON object with the following fields: + + .. code-block:: tsref + + interface RevealRequest { + + // Array of `n` new hash codes of denomination public keys to order. + new_denoms_h: HashCode[]; + + // Array of `n` entries with blinded coins, + // matching the respective entries in `new_denoms`. + coin_evs: CoinEnvelope[]; + + // `kappa - 1` transfer private keys (ephemeral ECDHE keys) + transfer_privs: EddsaPrivateKey[]; + + // transfer public key at the `noreveal_index`. + transfer_pub: EddsaPublicKey; + + // Array of `n` signatures made by the wallet using the old coin's private key, + // used later to verify the /refresh/link response from the exchange. + // Signs over a `TALER_CoinLinkSignaturePS`_ + link_sigs: EddsaSignature[]; + + // The original commitment, used to match the /refresh/reveal + // to the corresponding /refresh/melt operation. + rc: HashCode; + } + + + .. _RevealResponse: + .. code-block:: tsref + + interface RevealResponse { + // List of the exchange's blinded RSA signatures on the new coins. Each + // element in the array is another JSON object which contains the signature + // in the "ev_sig" field. + ev_sigs: BlindedRsaSignature[]; + } + + + .. _RevealConflictResponse: + .. code-block:: tsref + + interface RevealConflictResponse { + // Constant "commitment violation" + error: string; + + // Detailed error code + code: integer; + + // Commitment as calculated by the exchange from the revealed data. + rc_expected: HashCode; + + } + + +.. http:get:: /refresh/link + + Link the old public key of a melted coin to the coin(s) that were exchangeed during the refresh operation. + + **Request:** + + :query coin_pub: melted coin's public key + + **Response:** + + :status 200 OK: + All commitments were revealed successfully. The exchange returns an array, + typically consisting of only one element, in which each each element contains + information about a melting session that the coin was used in. + :status 404 Not Found: + The exchange has no linkage data for the given public key, as the coin has not + yet been involved in a refresh operation. + + **Details:** + + .. _tsref-type-LinkResponse: + .. code-block:: tsref + + interface LinkResponse { + // transfer ECDHE public key corresponding to the `coin_pub`, used to + // compute the blinding factor and private key of the fresh coins. + transfer_pub: EcdhePublicKey; + + // array with (encrypted/blinded) information for each of the coins + // exchangeed in the refresh operation. + new_coins: NewCoinInfo[]; + } + + .. _tsref-type-NewCoinInfo: + .. code-block:: tsref + + interface NewCoinInfo { + // RSA public key of the exchangeed coin. + denom_pub: RsaPublicKey; + + // Exchange's blinded signature over the exchangeed coin. + ev_sig: BlindedRsaSignature; + + // Blinded coin, to be verified by the wallet to protect against + // a malicious exchange. + coin_ev: CoinEnvelope; + + // Signature made by the old coin over the refresh request. + // Signs over a `TALER_CoinLinkSignaturePS`_ + link_sig: EddsaSignature; + } + + +------------------- +Emergency Cash-Back +------------------- + +This API is only used if the exchange is either about to go out of +business or has had its private signing keys compromised (so in +either case, the protocol is only used in **abnormal** +situations). In the above cases, the exchange signals to the +wallets that the emergency cash back protocol has been activated +by putting the affected denomination keys into the cash-back +part of the /keys response. If and only if this has happened, +coins that were signed with those denomination keys can be cashed +in using this API. + + .. note:: + + This is a proposed API, we are implementing it as bug #3887. + +.. http:post:: /payback + + Demand that a coin be refunded via wire transfer to the original owner. + + **Request:** The request body must be a `PaybackRequest`_ object. + + **Response:** + :status 200 OK: + The request was succesful, and the response is a `PaybackConfirmation`. + Note that repeating exactly the same request + will again yield the same response, so if the network goes down during the + transaction or before the client can commit the coin signature to disk, the + coin is not lost. + :status 401 Unauthorized: The coin's signature is invalid. + :status 403 Forbidden: The coin was already used for payment. + The response is a `DepositDoubleSpendError`_. + :status 404 Not Found: + The denomination key is not in the set of denomination + keys where emergency pay back is enabled, or the blinded + coin is not known to have been withdrawn. + + **Details:** + + .. _PaybackRequest: + .. code-block:: tsref + + interface PaybackRequest { + // Hash of denomination public key (RSA), specifying the type of coin the client + // would like the exchange to pay back. + denom_pub_hash: HashCode; + + // Signature over the `coin public key `_ by the denomination. + denom_sig: RsaSignature; + + // coin's public key + coin_pub: CoinPublicKey; + + // coin's blinding factor + coin_blind_key_secret: RsaBlindingKeySecret; + + // Signature of `TALER_PaybackRequestPS`_ created with the `coin's private key `_ + coin_sig: EddsaSignature; + + // Was the coin refreshed (and thus the payback should go to the old coin)? + // Optional (for backwards compatibility); if absent, "false" is assumed + refreshed?: boolean; + } + + + .. _PaybackConfirmation: + .. code-block:: tsref + + interface PaybackConfirmation { + // public key of the reserve that will receive the payback, + // provided if refreshed was false. + reserve_pub?: EddsaPublicKey; + + // public key of the old coin that will receive the payback, + // provided if refreshed was true. + old_coin_pub?: EddsaPublicKey; + + // How much will the exchange pay back (needed by wallet in + // case coin was partially spent and wallet got restored from backup) + amount: Amount; + + // Time by which the exchange received the /payback request. + timestamp: Timestamp; + + // the EdDSA signature of `TALER_PaybackConfirmationPS`_ (refreshed false) + // or `TALER_PaybackRefreshConfirmationPS_` (refreshed true) using a current + // `signing key of the exchange `_ affirming the successful + // payback request, and that the exchange promises to transfer the funds + // by the date specified (this allows the exchange delaying the transfer + // a bit to aggregate additional payback requests into a larger one). + exchange_sig: EddsaSignature; + + // Public EdDSA key of the exchange that was used to generate the signature. + // Should match one of the exchange's signing keys from /keys. It is given + // explicitly as the client might otherwise be confused by clock skew as to + // which signing key was used. + exchange_pub: EddsaPublicKey; + } + + +----------------------- +Tracking wire transfers +----------------------- + +This API is used by merchants that need to find out which wire +transfers (from the exchange to the merchant) correspond to which deposit +operations. Typically, a merchant will receive a wire transfer with a +**wire transfer identifier** and want to know the set of deposit +operations that correspond to this wire transfer. This is the +preferred query that merchants should make for each wire transfer they +receive. If a merchant needs to investigate a specific deposit +operation (i.e. because it seems that it was not paid), then the +merchant can also request the wire transfer identifier for a deposit +operation. + +Sufficient information is returned to verify that the coin signatures +are correct. This also allows governments to use this API when doing +a tax audit on merchants. + +Naturally, the returned information may be sensitive for the merchant. +We do not require the merchant to sign the request, as the same requests +may also be performed by the government auditing a merchant. +However, wire transfer identifiers should have sufficient entropy to +ensure that obtaining a successful reply by brute-force is not practical. +Nevertheless, the merchant should protect the wire transfer identifiers +from his bank statements against unauthorized access, least his income +situation is revealed to an adversary. (This is not a major issue, as +an adversary that has access to the line-items of bank statements can +typically also view the balance.) + + +.. http:get:: /track/transfer + + Provides deposits associated with a given wire transfer. + + **Request:** + + :query wtid: raw wire transfer identifier identifying the wire transfer (a base32-encoded value) + + **Response:** + + :status 200 OK: + The wire transfer is known to the exchange, details about it follow in the body. + The body of the response is a `TrackTransferResponse`_. + :status 404 Not Found: + The wire transfer identifier is unknown to the exchange. + + .. _TrackTransferResponse: + .. _tsref-type-TrackTransferResponse: + .. code-block:: tsref + + interface TrackTransferResponse { + // Total amount transferred + total: Amount; + + // Applicable wire fee that was charged + wire_fee: Amount; + + // public key of the merchant (identical for all deposits) + merchant_pub: EddsaPublicKey; + + // hash of the wire details (identical for all deposits) + H_wire: HashCode; + + // Time of the execution of the wire transfer by the exchange + execution_time: Timestamp; + + // details about the deposits + deposits: TrackTransferDetail[]; + + // signature from the exchange made with purpose + // `TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT` + exchange_sig: EddsaSignature; + + // public EdDSA key of the exchange that was used to generate the signature. + // Should match one of the exchange's signing keys from /keys. Again given + // explicitly as the client might otherwise be confused by clock skew as to + // which signing key was used. + exchange_pub: EddsaSignature; + } + + .. _tsref-type-TrackTransferDetail: + .. code-block:: tsref + + interface TrackTransferDetail { + // SHA-512 hash of the contact of the merchant with the customer. + h_contract_terms: HashCode; + + // coin's public key, both ECDHE and EdDSA. + coin_pub: CoinPublicKey; + + // The total amount the original deposit was worth. + deposit_value: Amount; + + // applicable fees for the deposit + deposit_fee: Amount; + + } + +.. http:post:: /track/transaction + + Provide the wire transfer identifier associated with an (existing) deposit operation. + + **Request:** The request body must be a `TrackTransactionRequest`_ JSON object. + + **Response:** + + :status 200 OK: + The deposit has been executed by the exchange and we have a wire transfer identifier. + The response body is a `TrackTransactionResponse`_ object. + :status 202 Accepted: + The deposit request has been accepted for processing, but was not yet + executed. Hence the exchange does not yet have a wire transfer identifier. The + merchant should come back later and ask again. + The response body is a `TrackTransactionAcceptedResponse`_. + :status 401 Unauthorized: The signature is invalid. + :status 404 Not Found: The deposit operation is unknown to the exchange + + **Details:** + + .. _tsref-type-TrackTransactionRequest: + .. _TrackTransactionRequest: + .. code-block:: tsref + + interface TrackTransactionRequest { + // SHA-512 hash of the merchant's payment details. + H_wire: HashCode; + + // SHA-512 hash of the contact of the merchant with the customer. + h_contract_terms: HashCode; + + // coin's public key, both ECDHE and EdDSA. + coin_pub: CoinPublicKey; + + // the EdDSA public key of the merchant, so that the client can identify + // the merchant for refund requests. + merchant_pub: EddsaPublicKey; + + // the EdDSA signature of the merchant made with purpose + // `TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION` , affirming that it is really the + // merchant who requires obtaining the wire transfer identifier. + merchant_sig: EddsaSignature; + } + + + .. _tsref-type-TrackTransactionResponse: + .. _TrackTransactionResponse: + .. code-block:: tsref + + interface TrackTransactionResponse { + // raw wire transfer identifier of the deposit. + wtid: Base32; + + // when was the wire transfer given to the bank. + execution_time: Timestamp; + + // The contribution of this coin to the total (without fees) + coin_contribution: Amount; + + // Total amount transferred + total_amount: Amount; + + // binary-only Signature_ for purpose `TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE` + // whereby the exchange affirms the successful wire transfer. + exchange_sig: EddsaSignature; + + // public EdDSA key of the exchange that was used to generate the signature. + // Should match one of the exchange's signing keys from /keys. Again given + // explicitly as the client might otherwise be confused by clock skew as to + // which signing key was used. + exchange_pub: EddsaPublicKey; + } + + .. _tsref-type-TrackTransactionAcceptedResponse: + .. _TrackTransactionAcceptedResponse: + .. code-block:: tsref + + interface TrackTransactionAcceptedResponse { + // time by which the exchange currently thinks the deposit will be executed. + execution_time: Timestamp; + } + + +------- +Refunds +------- + +.. _refund: +.. http:POST:: /refund + + Undo deposit of the given coin, restoring its value. + + **Request:** The request body must be a `RefundRequest`_ object. + + **Response:** + + :status 200 Ok: + The operation succeeded, the exchange confirms that the coin can now be refreshed. The response will include a `RefundSuccess`_ object. + :status 401 Unauthorized: + Merchant signature is invalid. + :status 404 Not found: + The refund operation failed as we could not find a matching deposit operation (coin, contract, transaction ID and merchant public key must all match). + :status 410 Gone: + It is too late for a refund by the exchange, the money was already sent to the merchant. + + **Details:** + + .. _RefundRequest: + .. code-block:: tsref + + interface RefundRequest { + + // Amount to be refunded, can be a fraction of the + // coin's total deposit value (including deposit fee); + // must be larger than the refund fee. + refund_amount: Amount; + + // Refund fee associated with the given coin. + // must be smaller than the refund amount. + refund_fee: Amount; + + // SHA-512 hash of the contact of the merchant with the customer. + h_contract_terms: HashCode; + + // coin's public key, both ECDHE and EdDSA. + coin_pub: CoinPublicKey; + + // 64-bit transaction id of the refund transaction between merchant and customer + rtransaction_id: number; + + // EdDSA public key of the merchant. + merchant_pub: EddsaPublicKey; + + // EdDSA signature of the merchant affirming the refund. + merchant_sig: EddsaPublicKey; + + } + + .. _RefundSuccess: + .. code-block:: tsref + + interface RefundSuccess { + // The string constant "REFUND_OK" + status: string; + + // the EdDSA :ref:`signature` (binary-only) with purpose + // `TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND` using a current signing key of the + // exchange affirming the successful refund + sig: EddsaSignature; + + // public EdDSA key of the exchange that was used to generate the signature. + // Should match one of the exchange's signing keys from /keys. It is given + // explicitly as the client might otherwise be confused by clock skew as to + // which signing key was used. + pub: EddsaPublicKey; + } + + +------------ +The Test API +------------ + +The test API is not there to test the exchange, but to allow +clients of the exchange (merchant and wallet implementations) +to test if their implemenation of the cryptography is +binary-compatible with the implementation of the exchange. + +.. http:POST:: /test/base32 + + Test hashing and Crockford :ref:`base32` encoding. + + **Request:** + + .. code-block:: tsref + + { + // some base32-encoded value + input: Base32; + } + + **Response:** + + .. code-block:: tsref + + { + // the base32_-encoded hash of the input value + output: Base32; + } + +.. http:POST:: /test/encrypt + + Test symmetric encryption. + + **Request:** + + .. code-block:: tsref + + { + // Some `base32`_-encoded value + input: Base32; + + // some `base32`_-encoded hash that is used to derive the symmetric key and + // initialization vector for the encryption using the HKDF with "skey" and + // "iv" as the salt. + key_hash: Base32; + } + + **Response:** + + + .. code-block:: tsref + + { + // the encrypted value + output: Base32; + } + +.. http:POST:: /test/hkdf + + Test Hash Key Deriviation Function. + + **Request:** + + + .. code-block:: tsref + + { + // Some `base32`_-encoded value + input: Base32; + } + + **Response:** + + + .. code-block:: tsref + + { + // the HKDF of the input using "salty" as salt + output: Base32; + } + +.. http:POST:: /test/ecdhe + + Test ECDHE. + + **Request:** + + .. code-block:: tsref + + { + ecdhe_pub: EcdhePublicKey; + ecdhe_priv: EcdhePrivateKey; + } + + **Response:** + + .. code-block:: tsref + + { + // ECDH result from the two keys + ecdhe_hash: HashCode; + } + + +.. http:POST:: /test/eddsa + + Test EdDSA. + + **Request:** + + .. code-block:: tsref + + { + eddsa_pub: EddsaPublicKey; + + // EdDSA signature using purpose TALER_SIGNATURE_CLIENT_TEST_EDDSA. Note: + // the signed payload must be empty, we sign just the purpose here. + eddsa_sig: EddsaSignature; + } + + **Response:** + + :status 200: the signature was valid + :status 401 Unauthorized: the signature was invalid + + The exchange responds with another valid signature, which gives the + client the opportunity to test its signature verification implementation. + + .. code-block:: tsref + + { + // Another EdDSA public key + eddsa_pub: EddsaPublicKey; + + // EdDSA signature using purpose TALER_SIGNATURE_EXCHANGE_TEST_EDDSA + eddsa_sig: EddsaSignature; + } + + +.. http:GET:: /test/rsa/get + + Obtain the RSA public key used for signing in /test/rsa/sign. + + **Response:** + + .. code-block:: tsref + + { + // The RSA public key the client should use when blinding a value for the /test/rsa/sign API. + rsa_pub: RsaPublicKey; + } + +.. http:POST:: /test/rsa/sign + + Test RSA blind signatures. + + **Request:** + + .. code-block:: tsref + + { + // Blinded value to sign. + blind_ev: BlindedRsaSignature; + } + + **Response:** + + + .. code-block:: tsref + + { + // Blind RSA signature over the `blind_ev` using the private key + // corresponding to the RSA public key returned by /test/rsa/get. + rsa_blind_sig: BlindedRsaSignature; + } + +.. http:POST:: /test/transfer + + Test Transfer decryption. + + **Request:** + + .. code-block:: tsref + + { + // Private transfer key + trans_priv: string; + + // `Coin public key `_ + coin_pub: EddsaPublicKey; + } + + **Response:** + + :status 200: the operation succeeded + + .. code-block:: tsref + + { + // Decrypted transfer secret + secret: string; + } diff --git a/core/api-merchant.rst b/core/api-merchant.rst new file mode 100644 index 00000000..9eb69812 --- /dev/null +++ b/core/api-merchant.rst @@ -0,0 +1,1194 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016, 2017 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING. If not, see + + @author Marcello Stanisci + @author Florian Dold + @author Christian Grothoff + +.. _merchant-api: + +==================== +Merchant Backend API +==================== + +------------------ +Receiving Payments +------------------ + +.. _post-order: + +.. http:post:: /order + + Create a new order that a customer can pay for. + + This request is not idempotent unless an `order_id` is explicitly specified. + + .. note:: + + This endpoint does not return a URL to redirect your user to confirm the payment. + In order to get this URL use :http:get:`/check-payment`. The API is structured this way + since the payment redirect URL is not unique for every order, there might be varying parameters + such as the session id. + + **Request:** + + The request must be a `PostOrderRequest`_. + + **Response** + + :status 200 OK: + The backend has successfully created the proposal. The response is a + `PostOrderResponse`_. + + .. _PostOrderRequest: + .. code-block:: tsref + + interface PostOrderRequest { + // The order must at least contain the minimal + // order detail, but can override all + order: MinimalOrderDetail | ContractTerms; + } + + The following fields of the `ContractTerms`_ + + .. _MinimalOrderDetail: + .. _tsref-type-MinimalOrderDetail: + .. code-block:: tsref + + interface MinimalOrderRequest { + // Amount to be paid by the customer + amount: Amount + + // Short summary of the order + summary: string; + + // URL that will show that the order was successful after + // it has been paid for. The wallet will always automatically append + // the order_id as a query parameter. + fulfillment_url: string; + + // Merchant instance to use (leave empty to use instance "default") + instance?: string; + } + + .. _PostOrderResponse: + .. code-block:: tsref + + interface PostOrderResponse { + // Order ID of the response that was just created + order_id: string; + } + + +.. http:get:: /check-payment + + Check the payment status of an order. If the order exists but is not payed yet, + the response provides a redirect URL. + When the user goes to this URL, they will be prompted for payment. + + **Request:** + + :query order_id: order id that should be used for the payment + :query instance: *Optional*. Instance used for the payment. Defaults to the instance with identifier "default". + :query session_id: *Optional*. Session ID that the payment must be bound to. If not specified, the payment is not session-bound. + + **Response:** + + Returns a `CheckPaymentResponse`_, whose format can differ based on the status of the payment. + + .. _CheckPaymentResponse: + .. code-block:: tsref + + type CheckPaymentResponse = CheckPaymentPaidResponse | CheckPaymentUnpaidResponse + + .. _CheckPaymentPaidResponse: + .. _tsref-type-CheckPaymentPaidResponse: + .. code-block:: tsref + + interface CheckPaymentPaidResponse { + paid: true; + + // Was the payment refunded (even partially) + refunded: boolean; + + // Amount that was refunded + refund_amount: Amount; + + // Contract terms + contract_terms: ContractTerms; + } + + .. _CheckPaymentUnpaidResponse: + .. _tsref-type-CheckPaymentUnpaidResponse: + .. code-block:: tsref + + interface CheckPaymentUnpaidResponse { + paid: false; + + // URI that the wallet must process to complete the payment. + taler_pay_uri: string; + + } + + +-------------- +Giving Refunds +-------------- + + +.. http:post:: /refund + + Increase the refund amount associated with a given order. The user should be + redirected to the `refund_redirect_url` to trigger refund processing in the wallet. + + **Request** + + The request body is a `RefundRequest`_ object. + + **Response** + + :status 200 OK: + The refund amount has been increased, the backend responds with a `MerchantRefundResponse`_ + :status 400 Bad request: + The refund amount is not consistent: it is not bigger than the previous one. + + .. _RefundRequest: + .. code-block:: tsref + + interface RefundRequest { + // Order id of the transaction to be refunded + order_id: string; + + // Amount to be refunded + refund: Amount; + + // Human-readable refund justification + reason: string; + + // Merchant instance issuing the request + instance?: string; + } + + .. _MerchantRefundResponse: + .. code-block:: tsref + + interface MerchantRefundResponse { + // Public key of the merchant + merchant_pub: string; + + + // Contract terms hash of the contract that + // is being refunded. + h_contract_terms: string; + + // The signed refund permissions, to be sent to the exchange. + refund_permissions: MerchantRefundPermission[]; + + // URL (handled by the backend) that will + // trigger refund processing in the browser/wallet + refund_redirect_url: string; + } + + .. _MerchantRefundPermission: + .. _tsref-type-MerchantRefundPermissoin: + .. code-block:: tsref + + interface MerchantRefundPermission { + // Amount to be refunded. + refund_amount: AmountJson; + + // Fee for the refund. + refund_fee: AmountJson; + + // Public key of the coin being refunded. + coin_pub: string; + + // Refund transaction ID between merchant and exchange. + rtransaction_id: number; + + // Signature made by the merchant over the refund permission. + merchant_sig: string; + } + + +-------------------- +Giving Customer Tips +-------------------- + + +.. http:post:: /tip-authorize + + Authorize a tip that can be picked up by the customer's wallet by POSTing to + `/tip-pickup`. Note that this is simply the authorization step the back + office has to trigger first. The user should be navigated to the `tip_redirect_url` + to trigger tip processing in the wallet. + + **Request** + + The request body is a `TipCreateRequest`_ object. + + **Response** + + :status 200 OK: + A tip has been created. The backend responds with a `TipCreateConfirmation`_ + :status 404 Not Found: + The instance is unknown to the backend, expired or was never enabled or + the reserve is unknown to the exchange or expired (see detailed status + either being TALER_EC_RESERVE_STATUS_UNKNOWN or + TALER_EC_TIP_AUTHORIZE_INSTANCE_UNKNOWN or + TALER_EC_TIP_AUTHORIZE_INSTANCE_DOES_NOT_TIP or + TALER_EC_TIP_AUTHORIZE_RESERVE_EXPIRED. + :status 412 Precondition Failed: + The tip amount requested exceeds the available reserve balance for tipping. + + .. _TipCreateRequest: + .. code-block:: tsref + + interface TipCreateRequest { + // Amount that the customer should be tipped + amount: Amount; + + // Merchant instance issuing the request + instance?: string; + + // Justification for giving the tip + justification: string; + + // URL that the user should be directed to after tipping, + // will be included in the tip_token. + next_url: string; + } + + .. _TipCreateConfirmation: + .. code-block:: tsref + + interface TipCreateConfirmation { + // Token that will be handed to the wallet, + // contains all relevant information to accept + // a tip. + tip_token: string; + + // URL that will directly trigger procesing + // the tip when the browser is redirected to it + tip_redirect_url: string; + } + + +.. http:post:: /tip-query + + Query the status of an instance's tipping reserve. + + **Request** + + :query instance: instance to query + + **Response** + + :status 200 OK: + A tip has been created. The backend responds with a `TipQueryResponse`_ + :status 404 Not Found: + The instance is unknown to the backend. + :status 412 Precondition Failed: + The instance does not have a tipping reserve configured. + + .. _TipQueryResponse: + .. code-block:: tsref + + interface TipQueryResponse { + // Amount still available + amount_available: Amount; + + // Amount that we authorized for tips + amount_authorized: Amount; + + // Amount that was picked up by users already + amount_picked_up: Amount; + + // Timestamp indicating when the tipping reserve will expire + expiration: Timestamp; + + // Reserve public key of the tipping reserve + reserve_pub: string; + } + + +------------------------ +Tracking Wire Transfers +------------------------ + +.. http:get:: /track/transfer + + Provides deposits associated with a given wire transfer. + + **Request** + + :query wtid: raw wire transfer identifier identifying the wire transfer (a base32-encoded value) + :query wire_method: name of the wire transfer method used for the wire transfer + :query exchange: base URL of the exchange that made the wire transfer + :query instance: (optional) identificative token of the merchant `instance `_ which is being tracked. + + **Response:** + + :status 200 OK: + The wire transfer is known to the exchange, details about it follow in the body. + The body of the response is a `MerchantTrackTransferResponse`_. Note that + the similarity to the response given by the exchange for a /track/transfer + is completely intended. + + :status 404 Not Found: + The wire transfer identifier is unknown to the exchange. + + :status 424 Failed Dependency: The exchange provided conflicting information about the transfer. Namely, + there is at least one deposit among the deposits aggregated by `wtid` that accounts for a coin whose + details don't match the details stored in merchant's database about the same keyed coin. + The response body contains the `TrackTransferConflictDetails`_. + + .. _MerchantTrackTransferResponse: + .. _tsref-type-TrackTransferResponse: + .. code-block:: tsref + + interface TrackTransferResponse { + // Total amount transferred + total: Amount; + + // Applicable wire fee that was charged + wire_fee: Amount; + + // public key of the merchant (identical for all deposits) + merchant_pub: EddsaPublicKey; + + // hash of the wire details (identical for all deposits) + H_wire: HashCode; + + // Time of the execution of the wire transfer by the exchange + execution_time: Timestamp; + + // details about the deposits + deposits_sums: TrackTransferDetail[]; + + // signature from the exchange made with purpose + // `TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT` + exchange_sig: EddsaSignature; + + // public EdDSA key of the exchange that was used to generate the signature. + // Should match one of the exchange's signing keys from /keys. Again given + // explicitly as the client might otherwise be confused by clock skew as to + // which signing key was used. + exchange_pub: EddsaSignature; + } + + .. _tsref-type-TrackTransferDetail: + .. code-block:: tsref + + interface TrackTransferDetail { + // Business activity associated with the wire transferred amount + // `deposit_value`. + order_id: string; + + // The total amount the exchange paid back for `order_id`. + deposit_value: Amount; + + // applicable fees for the deposit + deposit_fee: Amount; + } + + + **Details:** + + .. _tsref-type-TrackTransferConflictDetails: + .. _TrackTransferConflictDetails: + .. code-block:: tsref + + interface TrackTransferConflictDetails { + // Numerical `error code `_ + code: number; + + // Text describing the issue for humans. + hint: String; + + // A /deposit response matching `coin_pub` showing that the + // exchange accepted `coin_pub` for `amount_with_fee`. + exchange_deposit_proof: DepositSuccess; + + // Offset in the `exchange_transfer_proof` where the + // exchange's response fails to match the `exchange_deposit_proof`. + conflict_offset: number; + + // The response from the exchange which tells us when the + // coin was returned to us, except that it does not match + // the expected value of the coin. + exchange_transfer_proof: TrackTransferResponse; + + // Public key of the coin for which we have conflicting information. + coin_pub: EddsaPublicKey; + + // Merchant transaction in which `coin_pub` was involved for which + // we have conflicting information. + transaction_id: number; + + // Expected value of the coin. + amount_with_fee: Amount; + + // Expected deposit fee of the coin. + deposit_fee: Amount; + + } + + +.. http:get:: /track/transaction + + Provide the wire transfer identifier associated with an (existing) deposit operation. + + **Request:** + + :query id: ID of the transaction we want to trace (an integer) + :query instance: merchant instance + + **Response:** + + :status 200 OK: + The deposit has been executed by the exchange and we have a wire transfer identifier. + The response body is a JSON array of `TransactionWireTransfer`_ objects. + :status 202 Accepted: + The deposit request has been accepted for processing, but was not yet + executed. Hence the exchange does not yet have a wire transfer identifier. + The merchant should come back later and ask again. + The response body is a :ref:`TrackTransactionAcceptedResponse `. Note that + the similarity to the response given by the exchange for a /track/order + is completely intended. + :status 404 Not Found: The transaction is unknown to the backend. + :status 424 Failed Dependency: + The exchange previously claimed that a deposit was not included in a wire + transfer, and now claims that it is. This means that the exchange is + dishonest. The response contains the cryptographic proof that the exchange + is misbehaving in the form of a `TransactionConflictProof`_. + + **Details:** + + .. _tsref-type-TransactionWireTransfer: + .. _TransactionWireTransfer: + .. code-block:: tsref + + interface TransactionWireTransfer { + + // Responsible exchange + exchange_uri: string; + + // 32-byte wire transfer identifier + wtid: Base32; + + // execution time of the wire transfer + execution_time: Timestamp; + + // Total amount that has been wire transfered + // to the merchant + amount: Amount; + } + + .. _tsref-type-CoinWireTransfer: + .. _CoinWireTransfer: + .. code-block:: tsref + + interface CoinWireTransfer { + // public key of the coin that was deposited + coin_pub: EddsaPublicKey; + + // Amount the coin was worth (including deposit fee) + amount_with_fee: Amount; + + // Deposit fee retained by the exchange for the coin + deposit_fee: Amount; + } + + .. _TransactionConflictProof: + .. _tsref-type-TransactionConflictProof: + .. code-block:: tsref + + interface TransactionConflictProof { + // Numerical `error code `_ + code: number; + + // Human-readable error description + hint: string; + + // A claim by the exchange about the transactions associated + // with a given wire transfer; it does not list the + // transaction that `transaction_tracking_claim` says is part + // of the aggregate. This is + // a `/track/transfer` response from the exchange. + wtid_tracking_claim: TrackTransferResponse; + + // The current claim by the exchange that the given + // transaction is included in the above WTID. + // (A response from `/track/order`). + transaction_tracking_claim: TrackTransactionResponse; + + // Public key of the coin for which we got conflicting information. + coin_pub: CoinPublicKey; + + } + + +------------------- +Transaction history +------------------- + +.. http:get:: /history + + Returns transactions up to some point in the past + + **Request** + + :query date: time threshold, see `delta` for its interpretation. + :query start: row number threshold, see `delta` for its interpretation. Defaults to `UINT64_MAX`, namely the biggest row id possible in the database. + :query delta: takes value of the form `N (-N)`, so that at most `N` values strictly younger (older) than `start` and `date` are returned. Defaults to `-20`. + :query instance: on behalf of which merchant instance the query should be accomplished. + :query ordering: takes value `descending` or `ascending` according to the results wanted from younger to older or vice versa. Defaults to `descending`. + + **Response** + + :status 200 OK: The response is a JSON `array` of `TransactionHistory`_. The array is sorted such that entry `i` is younger than entry `i+1`. + + .. _tsref-type-TransactionHistory: + .. _TransactionHistory: + .. code-block:: tsref + + interface TransactionHistory { + // The serial number this entry has in the merchant's DB. + row_id: number; + + // order ID of the transaction related to this entry. + order_id: string; + + // Transaction's timestamp + timestamp: Timestamp; + + // Total amount associated to this transaction. + amount: Amount; + } + +.. _proposal: + + +------------------------- +Dynamic Merchant Instance +------------------------- + +.. note:: + + The endpoints to dynamically manage merchant instances has not been + implemented yet. The bug id for this refernce is 5349. + +.. http:get:: /instances + + This is used to return the list of all the merchant instances + + **Response** + + :status 200 OK: + The backend has successfully returned the list of instances stored. Returns + a `InstancesResponse`_. + + .. _InstancesResponse: + .. code-block:: tsref + + interface InstancesResponse { + // List of instances that are present in the backend(see `below `_) + instances: Instance[]; + } + +The `instance` object describes the instance registered with the backend. It has the following structure: + + .. Instance: + .. _tsref-type-Instance: + .. code-block:: tsref + + interface Instance { + // Merchant name corresponding to this instance. + name: string; + + // The URL where the wallet will send coins. + payto: string; + + // Merchant instance of the response to create + instance: string; + + //unique key for each merchant + merchant_id: string; + } + + +.. http:put:: /instances/ + + This request will be used to create a new merchant instance in the backend. + + **Request** + + The request must be a `CreateInstanceRequest`_. + + **Response** + + :status 200 OK: + The backend has successfully created the instance. The response is a + `CreateInstanceResponse`_. + + .. _CreateInstanceRequest: + .. code-block:: tsref + + interface CreateInstanceRequest { + // The URL where the wallet has to send coins. + // payto://-URL of the merchant's bank account. Required. + payto: string; + + // Merchant instance of the response to create + // This field is optional. If it is not specified + // then it will automatically be created. + instance?: string; + + // Merchant name corresponding to this instance. + name: string; + + } + + .. _CreateInstanceResponse: + .. code-block:: tsref + + interface CreateInstanceResponse { + // Merchant instance of the response that was created + instance: string; + + //unique key for each merchant + merchant_id: string; + } + + +.. http:get:: /instances/ + + This is used to query a specific merchant instance. + + **Request:** + + :query instance_id: instance id that should be used for the instance + + **Response** + + :status 200 OK: + The backend has successfully returned the list of instances stored. Returns + a `QueryInstancesResponse`_. + + .. _QueryInstancesResponse: + .. code-block:: tsref + + interface QueryInstancesResponse { + // The URL where the wallet has to send coins. + // payto://-URL of the merchant's bank account. Required. + payto: string; + + // Merchant instance of the response to create + // This field is optional. If it is not specified + // then it will automatically be created. + instance?: string; + + // Merchant name corresponding to this instance. + name: string; + + } + + +.. http:post:: /instances/ + + This request will be used to update merchant instance in the backend. + + + **Request** + + The request must be a `PostInstanceUpdateRequest`_. + + **Response** + + :status 200 OK: + The backend has successfully updated the instance. The response is a + `PostInstanceUpdateResponse`_. + + .. _PostInstanceUpdateRequest: + .. code-block:: tsref + + interface PostInstanceUpdateRequest { + // Merchant instance that is to be updaated. Required. + instance: string; + + // New URL where the wallet has to send coins. + // payto://-URL of the merchant's bank account. Required. + payto: string; + + // Merchant name coreesponding to this instance. + name: string; + + } + + .. _PostInstanceUpdateResponse: + .. code-block:: tsref + + interface PostInstanceUpdateResponse { + // Merchant instance of the response that was updated + instance: string; + + //unique key for each merchant + merchant_id: string; + } + + +.. http:delete:: /instances/ + + This request will be used to delete merchant instance in the backend. + + **Request:** + + :query instance_id: instance id that should be used for the instance + + **Response** + + :status 200 OK: + The backend has successfully removed the instance. The response is a + `PostInstanceRemoveResponse`_. + + .. _PostInstanceRemoveResponse: + .. code-block:: tsref + + interface PostInstanceRemoveResponse { + deleted: true; + } + + +------------------ +The Contract Terms +------------------ + +The `contract terms` must have the following structure: + + .. _ContractTerms: + .. _tsref-type-ContractTerms: + .. code-block:: tsref + + interface ContractTerms { + // Human-readable description of the whole purchase + summary: string; + + // Unique, free-form identifier for the proposal. + // Must be unique within a merchant instance. + // For merchants that do not store proposals in their DB + // before the customer paid for them, the order_id can be used + // by the frontend to restore a proposal from the information + // encoded in it (such as a short product identifier and timestamp). + order_id: string; + + // Total price for the transaction. + // The exchange will subtract deposit fees from that amount + // before transfering it to the merchant. + amount: Amount; + + // The URL where the wallet has to send coins. + pay_url: string; + + // The URL for this purchase. Every time is is visited, the merchant + // will send back to the customer the same proposal. Clearly, this URL + // can be bookmarked and shared by users. + fulfillment_url: string; + + // Maximum total deposit fee accepted by the merchant for this contract + max_fee: Amount; + + // Maximum wire fee accepted by the merchant (customer share to be + // divided by the 'wire_fee_amortization' factor, and further reduced + // if deposit fees are below 'max_fee'). Default if missing is zero. + max_wire_fee: Amount; + + // Over how many customer transactions does the merchant expect to + // amortize wire fees on average? If the exchange's wire fee is + // above 'max_wire_fee', the difference is divided by this number + // to compute the expected customer's contribution to the wire fee. + // The customer's contribution may further be reduced by the difference + // between the 'max_fee' and the sum of the actual deposit fees. + // Optional, default value if missing is 1. 0 and negative values are + // invalid and also interpreted as 1. + wire_fee_amortization: Integer; + + // List of products that are part of the purchase (see `below `_) + products: Product[]; + + // Time when this contract was generated + timestamp: Timestamp; + + // After this deadline has passed, no refunds will be accepted. + refund_deadline: Timestamp; + + // After this deadline, the merchant won't accept payments for the contact + pay_deadline: Timestamp; + + // Merchant's public key used to sign this proposal; this information + // is typically added by the backend Note that this can be an ephemeral key. + merchant_pub: EddsaPublicKey; + + // More info about the merchant, see below + merchant: Merchant; + + // The hash of the merchant instance's wire details. + H_wire: HashCode; + + // Wire transfer method identifier for the wire method associated with H_wire. + // The wallet may only select exchanges via a matching auditor if the + // exchange also supports this wire method. + // The wire transfer fees must be added based on this wire transfer method. + wire_method: string; + + // Any exchanges audited by these auditors are accepted by the merchant. + auditors: Auditor[]; + + // Exchanges that the merchant accepts even if it does not accept any auditors that audit them. + exchanges: Exchange[]; + + // Map from labels to locations + locations: { [label: string]: [location: Location], ... }; + + // Nonce generated by the wallet and echoed by the merchant + // in this field when the proposal is generated. + nonce: string; + + // Extra data that is only interpreted by the merchant frontend. + // Useful when the merchant needs to store extra information on a + // contract without storing it separately in their database. + extra?: any; + } + + The wallet must select a exchange that either the mechant accepts directly by + listing it in the exchanges arry, or for which the merchant accepts an auditor + that audits that exchange by listing it in the auditors array. + + The `product` object describes the product being purchased from the merchant. It has the following structure: + + .. _Product: + .. _tsref-type-Product: + .. code-block:: tsref + + interface Product { + // Human-readable product description. + description: string; + + // The quantity of the product to deliver to the customer (optional, if applicable) + quantity?: string; + + // The price of the product; this is the total price for the amount specified by `quantity` + price: Amount; + + // merchant-internal identifier for the product + product_id?: string; + + // a list of objects indicating a `taxname` and its amount. Again, italics denotes the object field's name. + taxes?: any[]; + + // time indicating when this product should be delivered + delivery_date: Timestamp; + + // where to deliver this product. This may be an URL for online delivery + // (i.e. `http://example.com/download` or `mailto:customer@example.com`), + // or a location label defined inside the proposition's `locations`. + // The presence of a colon (`:`) indicates the use of an URL. + delivery_location: string; + } + + .. _tsref-type-Merchant: + .. code-block:: ts + + interface Merchant { + // label for a location with the business address of the merchant + address: string; + + // the merchant's legal name of business + name: string; + + // label for a location that denotes the jurisdiction for disputes. + // Some of the typical fields for a location (such as a street address) may be absent. + jurisdiction: string; + + // Which instance is working this proposal. + // See `Merchant Instances `_. + // This field is optional, as the "default" instance is not forced to provide any + // `instance` identificator. + instance: string; + } + + + .. _tsref-type-Location: + .. _Location: + .. code-block:: ts + + interface Location { + country?: string; + city?: string; + state?: string; + region?: string; + province?: string; + zip_code?: string; + street?: string; + street_number?: string; + } + + .. _tsref-type-Auditor: + .. code-block:: tsref + + interface Auditor { + // official name + name: string; + + // Auditor's public key + auditor_pub: EddsaPublicKey; + + // Base URL of the auditor + url: string; + } + + .. _tsref-type-Exchange: + .. code-block:: tsref + + interface Exchange { + // the exchange's base URL + url: string; + + // master public key of the exchange + master_pub: EddsaPublicKey; + } + + +------------------- +Customer-facing API +------------------- + +The `/public/*` endpoints are publicly exposed on the internet and accessed +both by the user's browser and their wallet. + + +.. http:post:: /public/pay + + Pay for a proposal by giving a deposit permission for coins. Typically used by + the customer's wallet. Can also be used in `abort-refund` mode to refund coins + that were already deposited as part of a failed payment. + + **Request:** + + The request must be a :ref:`pay request `. + + **Response:** + + :status 200 OK: + The exchange accepted all of the coins. The body is a `PaymentResponse`_ if the request used the mode "pay", or a `MerchantRefundResponse`_ if the request used was the mode "abort-refund". + The `frontend` should now fullfill the contract. + :status 412 Precondition Failed: + The given exchange is not acceptable for this merchant, as it is not in the + list of accepted exchanges and not audited by an approved auditor. + :status 401 Unauthorized: + One of the coin signatures was not valid. + :status 403 Forbidden: + The exchange rejected the payment because a coin was already spent before. + The response will include the `coin_pub` for which the payment failed, + in addition to the response from the exchange to the `/deposit` request. + + The `backend` will return verbatim the error codes received from the exchange's + :ref:`deposit ` API. If the wallet made a mistake, like by + double-spending for example, the `frontend` should pass the reply verbatim to + the browser/wallet. This should be the expected case, as the `frontend` + cannot really make mistakes; the only reasonable exception is if the + `backend` is unavailable, in which case the customer might appreciate some + reassurance that the merchant is working on getting his systems back online. + + .. _PaymentResponse: + .. code-block:: tsref + + interface PaymentResponse { + // Signature on `TALER_PaymentResponsePS`_ with the public + // key of the instance in the proposal. + sig: EddsaSignature; + + // Proposal data hash being signed over + h_proposal_data: HashCode; + + // Proposal, send for convenience so the frontend + // can do order processing without a second lookup on + // a successful payment + proposal: Proposal; + } + + + .. _tsref-type-Proposal: + .. code-block:: tsref + + interface Proposal { + // The proposal data, effectively the frontend's order with some data filled in + // by the merchant backend. + data: ProposalData; + + // Contract's hash, provided as a convenience. All components that do + // not fully trust the merchant must verify this field. + H_proposal: HashCode; + + // Signature over the hashcode of `proposal` made by the merchant. + merchant_sig: EddsaSignature; + } + + + .. _PayRequest: + .. code-block:: tsref + + interface PayRequest { + // Signature on `TALER_PaymentResponsePS`_ with the public + // key of the instance in the proposal. + sig: EddsaSignature; + + // Proposal data hash being signed over + h_proposal_data: HashCode; + + // Proposal, send for convenience so the frontend + // can do order processing without a second lookup on + // a successful payment + proposal: Proposal; + + // Coins with signature. + coins: CoinPaySig[]; + + // The merchant public key, used to uniquely + // identify the merchant instance. + merchant_pub: string; + + // Order ID that's being payed for. + order_id: string; + + // Mode for /pay ("pay" or "abort-refund") + mode: "pay" | "abort-refund"; + } + + +.. http:get:: /public/proposal + + Retrieve and take ownership (via nonce) over a proposal. + + **Request** + + :query instance: the merchant instance issuing the request + :query order_id: the order id whose refund situation is being queried + :query nonce: the nonce for the proposal + + **Response** + + :status 200 OK: + The backend has successfully retrieved the proposal. It responds with a :ref:`proposal `. + + :status 403 Forbidden: + The frontend used the same order ID with different content in the order. + + +.. http:post:: /public/tip-pickup + + Handle request from wallet to pick up a tip. + + **Request** + + The request body is a `TipPickupRequest`_ object. + + **Response** + + :status 200 OK: + A tip is being returned. The backend responds with a `TipResponse`_ + :status 401 Unauthorized: + The tip amount requested exceeds the tip. + :status 404 Not Found: + The tip identifier is unknown. + :status 409 Conflict: + Some of the denomination key hashes of the request do not match those currently available from the exchange (hence there is a conflict between what the wallet requests and what the merchant believes the exchange can provide). + + .. _TipPickupRequest: + .. code-block:: tsref + + interface TipPickupRequest { + + // Identifier of the tip. + tip_id: HashCode; + + // List of planches the wallet wants to use for the tip + planchets: PlanchetDetail[]; + } + + interface PlanchetDetail { + // Hash of the denomination's public key (hashed to reduce + // bandwidth consumption) + denom_pub_hash: HashCode; + + // coin's blinded public key + coin_ev: CoinEnvelope; + + } + + .. _TipResponse: + .. code-block:: tsref + + interface TipResponse { + // Public key of the reserve + reserve_pub: EddsaPublicKey; + + // The order of the signatures matches the planchets list. + reserve_sigs: EddsaSignature[]; + } + + +.. http:get:: /public/refund + + Pick up refunds for an order. + + **Request** + + :query instance: the merchant instance issuing the request + :query order_id: the order id whose refund situation is being queried + + **Response** + + If case of success, an *array of* `RefundLookup`_ objects is returned. + + .. _RefundLookup: + .. code-block:: tsref + + interface RefundLookup { + + // Coin from which the refund is going to be taken + coin_pub: EddsaPublicKey; + + // Refund amount taken from coin_pub + refund_amount: Amount; + + // Refund fee + refund_fee: Amount; + + // Identificator of the refund + rtransaction_id: number; + + // Merchant public key + merchant_pub: EddsaPublicKey + + // Merchant signature of a TALER_RefundRequestPS object + merchant_sig: EddsaSignature; + } + + +.. http:get:: /public/trigger-pay + + Used to trigger processing of payments, refunds and tips in the browser. The exact behavior + can be dependent on the user's browser. diff --git a/core/api-sync.rst b/core/api-sync.rst new file mode 100644 index 00000000..701c7df5 --- /dev/null +++ b/core/api-sync.rst @@ -0,0 +1,407 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING. If not, see + + @author Christian Grothoff + +.. _sync-api: + +============================================= +Wallet Backup and Synchronization Service API +============================================= + +The wallet backup and synchronization service uses an EdDSA wallet key +to identify the "account" of the user. The wallet key is Crockford +Base32-encoded in the URI to access the data and used to sign requests +as well as to encrypt the contents (see below). These signatures are +provided in detached from as HTTP headers. + +Once the user activates backup or synchronization, the wallet should +display the wallet key as a QR code as well as in text format together +with the synchronization service's URL and ask the user to print this +key material and keep it safe. + +The actual format of the wallet database is not relevant for the +backup and synchronization service, as the service must only ever see +a padded and encrypted version of the data. + +However, there are a few general rules that will apply to +any version of the wallet database. Still, except for the +32 byte minimum upload size, the synchronization service +itself cannot not enforce these rules. + + * First, the database should be compressed (i.e. gzip), then + padded to a power of 2 in kilobytes or a multiple of + megabytes, then encrypted and finally protected with + an HDKF. + * The encryption should use an ephemeral Curve25519 point that + is prefixed to the actual database, and combined with + the private wallet key via ECDH to create a symmetric secret. + With every revision of the wallet (but only real + revisions or merge operations), a fresh ephemeral must be + used to ensure that the symmetric secret differs every + time. HKDFs are used to derive symmetric key material + for authenticated encryption (encrypt-then-mac or a + modern AEAD-cipher like Keccak). Given that AES is more + easily available and will likey increase the code of + the wallet less, AES plus a SHA-512 HMAC should suffice + for now. + * The wallet must enable merging databases in a way that is + associative and commutative. For most activities, this implies + merging lists, applying expirations, dropping duplicates and + sorting the result. For deletions (operations by which the user + removed records prior to their scheduled expiration), it means + keeping a summarizing log of all deletion operations and applying + the deletions after each merge. A summarizing log of a deletion + operation would combine two deletion operations of the form + "delete all transactions smaller than amount X before time T" and + "delete all transactions smaller than amount Y before time T" + into "delete all transactions smaller than amount max(X,Y) before + time T". Similar summarizations should be applied to all + deletion operations supported by the wallet. Deletion operations + themselves are associated with an expiration time reflecting the + expiration of the longest lasting record that they explicitly + deleted. + Purchases do not have an expiration time, thus they create + a challenge if an indivdiual purchase is deleted. Thus, when + an individual purchase is deleted, the wallet is to keep track + of the deletion with a deletion record. The deletion record + still includes the purchase amount and purchase date. Thus, + when purchases are deleted "in bulk" in a way that would have + covered the individual deletion, such deletion records may + still be subsumed by a more general deletion clause. In addition + to the date and amount, the deletion record should only contain + a salted hash of the original purchase record's primary key, + so as to minimize information leakage. + * The database should contain a "last modified" timestamp to ensure + we do not go backwards in time if the synchronization service is + malicious. Merging two databases means taking the max of the + "last modified" timestamps, not setting it to the current time. + The wallet should reject a "fast forward" database update if the + result would imply going back in time. If the wallet receives a + database with a timestamp into the future, it must still + increment it by the smallest possible amount when uploading an + update. + +It is assumed that the synchronization service is only ever accessed +over TLS, and that the synchronization service is trusted to not build +user's location profiles by linking client IP addresses and wallet +keys. + + +-------------------------- +Receiving Terms of Service +-------------------------- + +.. http:get:: /terms + + Obtain the terms of service provided by the storage service. + + **Response:** + + Returns a `SyncTermsOfServiceResponse`_. + + .. _SyncTermsOfServiceResponse: + .. _tsref-type-SyncTermsOfServiceResponse: + .. code-block:: tsref + + interface SyncTermsOfServiceResponse { + // maximum wallet database backup size supported + storage_limit_in_megabytes: number; + + // maximum number of sync requests per day (per account) + daily_sync_limit: number; + + // how long after an account (or device) becomes dormant does the + // service expire the respective records? + inactive_expiration: relative-time; + + // Fee for an account, per year. + annual_fee: Amount; + + } + + +.. http:get:: /salt + + Obtain the salt used by the storage service. + + + **Response:** + + Returns a `SaltResponse`_. + + .. _SaltResponse: + .. _tsref-type-SaltResponse: + .. code-block:: tsref + + interface SaltResponse { + // salt value, at least 128 bits of entropy + salt: string; + } + + +.. _sync: + +.. http:get:: /$WALLET-KEY + + Download latest version of the wallet database. + The returned headers must include "Etags" based on + the hash of the (encrypted) database. The server must + check the client's caching headers and only return the + full database if it has changed since the last request + of the client. + + This method is generally only performed once per device + when the private key and URL of a synchronization service are + first given to the wallet on the respective device. Once a + wallet has a database, it should always use the POST method. + + A signature is not required, as (1) the wallet-key should + be reasonably private and thus unauthorized users should not + know how to produce the correct request, and (2) the + information returned is encrypted to the private key anyway + and thus virtually useless even to an attacker who somehow + managed to obtain the public key. + + **Response** + + :status 200 OK: + The body contains the current version of the wallet's + database as known to the server. + + :status 204 No content: + This is a fresh account, no previous wallet data exists at + the server. + + :status 402 Payment required: + The synchronization service requires payment before the + account can continue to be used. The fulfillment URL + should be the /$WALLET-KEY URL, but can be safely ignored + by the wallet. The contract should be shown to the user + in the canonical dialog, possibly in a fresh tab. + + :status 410 Gone: + The backup service has closed operations. The body will + contain the latest version still available at the server. + The body may be empty if no version is available. + The user should be urged to find another provider. + + :status 429 Too many requests: + This account has exceeded daily thresholds for the number of + requests. The wallet should try again later, and may want + to decrease its synchronization frequency. + + .. note:: + + "200 OK" responses include an HTTP header + "X-Taler-Sync-Signature" with the signature of the + wallet from the orginal upload, and an + "X-Taler-Sync-Previous" with the version that was + being updated (unless this is the first revision). + "X-Taler-Sync-Previous" is only given to enable + signature validation. + + +.. http:post:: /$WALLET-KEY + + Upload a new version of the wallet's database, or download the + latest version. The request must include the "Expect: 100 Continue" + header. The client must wait for "100 Continue" before proceeding + with the upload, regardless of the size of the upload. + + **Request** + + The request must include a "If-Match" header indicating the latest + version of the wallet's database known to the client. If the server + knows a more recent version, it will respond with a "409 conflict" + and return the server's version in the response. The client must + then merge the two versions before retrying the upload. Note that + a "409 Conflict" response will typically be given before the upload, + (instead of "100 continue"), but may also be given after the upload, + for example due to concurrent activities from other wallets on the + same account! + + The request must also include an "X-Taler-Sync-Signature" signing + the "If-Match" SHA-512 value and the SHA-512 hash of the body with + the wallet private key. + + Finally, the SHA-512 hash of the body must also be given in an + "E-tag" header of the request (so that the signature can be verified + before the upload is allowed to proceed). We note that the use + of "E-tag" in HTTP requests is non-standard, but in this case + logical. + + The uploaded body must have at least 32 bytes of payload (see + suggested upload format beginning with an ephemeral key). + + + **Response** + + :status 204 No content: + The transfer was successful, and the server has registered + the new version. + + :status 304 Not modified: + The server is already aware of this version of the wallet. + Returned before 100 continue to avoid upload. + + :status 400 Bad request: + Most likely, the uploaded body is too short (less than 32 bytes). + + :status 401 Unauthorized: + The signature is invalid or missing (or body does not match). + + :status 402 Payment required: + The synchronization service requires payment before the + account can continue to be used. The fulfillment URL + should be the /$WALLET-KEY URL, but can be safely ignored + by the wallet. The contract should be shown to the user + in the canonical dialog, possibly in a fresh tab. + + :status 409 Conflict: + The server has a more recent version than what is given + in "If-Match". The more recent version is returned. The + client should merge the two versions and retry using the + given response's "E-Tag" in the next attempt in "If-Match". + + :status 410 Gone: + The backup service has closed operations. The body will + contain the latest version still available at the server. + The body may be empty if no version is available. + The user should be urged to find another provider. + + :status 411 Length required: + The client must specify the "Content-length" header before + attempting upload. While technically optional by the + HTTP specification, the synchronization service may require + the client to provide the length upfront. + + :status 413 Request Entity Too Large: + The requested upload exceeds the quota for the type of + account. The wallet should suggest to the user to + migrate to another backup and synchronization service + (like with "410 Gone"). + + :status 429 Too many requests: + This account has exceeded daily thresholds for the number of + requests. The wallet should try again later, and may want + to decrease its synchronization frequency. + + .. note:: + + Responses with a body include an HTTP header + "X-Taler-Sync-Signature" with the signature of the + wallet from the orginal upload, and an + "X-Taler-Sync-Previous" with the version that was + being updated (unless this is the first revision). + "X-Taler-Sync-Previous" is only given to enable + signature validation. + + + +--------------------------- +Special constraints for Tor +--------------------------- + +We might introduce the notion of a "constraint" into the wallet's +database that states that the database is a "Tor wallet". Then, +synchronizing a "Tor-wallet" with a non-Tor wallet should trigger a +stern warning and require user confirmation (as otherwise +cross-browser synchronization may weaken the security of Tor browser +users). + + +------------------------------------------------ +Discovery of backup and synchronization services +------------------------------------------------ + +The wallet should keep a list of "default" synchronization services +per currency (by the currency the synchronization service accepts +for payment). If a synchronization service is entirely free, it +should be kept in a special list that is always available. + +Extending (or shortening) the list of synchronization services should +be possible using the same mechanism that is used to add/remove +auditors or exchanges. + +The wallet should urge the user to make use of a synchronization +service upon first withdrawal, suggesting one that is free or +accepts payment in the respective currency. If none is available, +the wallet should warn the user about the lack of availalable +backups and synchronization and suggest to the user to find a +reasonable service. Once a synchronization service was selected, +the wallet should urge the user to print the respective key +material. + +When the wallet starts the first time on a new device, it should +ask the user if he wants to synchronize with an existing wallet, +and if so, ask the user to enter the respective key and the +(base) URL of the synchronization service. + + +------------------------- +Synchronization frequency +------------------------- + +Generally, the wallet should attempt to synchronize at a randomized +time interval between 30 and 300 seconds of being started, unless it +already synchronized less than two hours ago already. Afterwards, +the wallet should synchronize every two hours, or after purchases +exceed 5 percent of the last bulk amount that the user withdrew. +In all cases the exact time of synchronization should be randomized +between 30 and 300 seconds of the specified event, both to minimize +obvious correlations and to spread the load. + +If the two hour frequency would exceed half of the rate budget offered +by the synchronization provider, it should be reduced to remain below +that threshold. + + +------------------------------- +Synchronization user experience +------------------------------- + +The menu should include three entries for synchronization: + +* "synchronize" to manually trigger synchronization, + insensitive if no synchronization provider is available +* "export backup configuration" to re-display (and possibly + print) the synchronization and backup parameters (URL and + private key), insensitive if no synchronization + provider is available, and +* "import backup configuration" to: + + * import another devices' synchronization options + (by specifying URL and private key, or possibly + scanning a QR code), or + * select a synchronization provider from the list, + including manual specification of a URL; here + confirmation should only be possible if the provider + is free or can be paid for; in this case, the + wallet should trigger the payment interaction when + the user presses the "select" button. + * a special button to "disable synchronization and backup" + +One usability issue here is that we are asking users to deal with a +private key. It is likely better to map private keys to trustwords +(PEP-style). Also, when putting private keys into a QR code, there is +the danger of the QR code being scanned and interpreted as a "public" +URL. Thus, the QR code should use the schema +"taler-sync://$SYNC-DOMAIN/$SYNC-PATH#private-key" where +"$SYNC-DOMAIN" is the domainname of the synchronization service and +$SYNC-PATH the (usually empty) path. By putting the private key after +"#", we may succeed in disclosing the value even to eager Web-ish +interpreters of URLs. Note that the actual synchronization service +must use the HTTPS protocol, which means we can leave out this prefix. diff --git a/core/index.rst b/core/index.rst new file mode 100644 index 00000000..76b77903 --- /dev/null +++ b/core/index.rst @@ -0,0 +1,40 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014-2018 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING. If not, see + + @author Florian Dold + @author Benedikt Muller + @author Sree Harsha Totakura + @author Marcello Stanisci + @author Christian Grothoff + +--------------------------- +Core Protocol Specification +--------------------------- + +The *Protocol Specification* defines the HTTP-based, predominantly RESTful +interfaces between the core components of Taler. + +.. toctree:: + :maxdepth: 2 + + api-common + api-error + api-exchange + api-merchant + api-auditor + api-bank + wireformats + api-sync + taler-uri diff --git a/core/taler-uri.rst b/core/taler-uri.rst new file mode 100644 index 00000000..d69b4b0c --- /dev/null +++ b/core/taler-uri.rst @@ -0,0 +1,84 @@ +==================== +The taler URI scheme +==================== + +The `taler` URI scheme represents actions that are processed by a Taler wallet. The basic syntax is as follows: + +.. code:: none + + 'taler://' action '/' params + +-------------------- +Requesting a Payment +-------------------- + +Payments are requested with the `pay` action. The parameters are a hierarchical identifier for the requested payment: + + +.. code:: none + + 'taler://pay/' merchant-host '/' merchant-query '/' merchant-instance '/' order-id [ '/' session-id ] + +The components `merchant-host`, `merchant-query` and `order-id` identify the URL that is used to claim the contract +for this payment request. + +To make the URI shorter (which is important for QR code payments), `-` (minus) can be substituted to get a default value +for some components: + +* the default for `merchant-instance` is `default` +* the default for `merchant-query` is `/public/proposal` + +The following is a minimal example for a payment request from the demo merchant, using the default instance and no session-bound payment: + +.. code:: none + + taler://pay/backend.demo.taler.net/-/-/2019.08.26-ABCED + + +----------- +Withdrawing +----------- + +.. code:: none + + 'taler://withdraw/' bank-host '/' bank-query '/' withdraw-uid + +When `bank-query` is `-`, the default `withdraw-operation` will be used. + +Example: + +.. code:: none + + 'taler://withdraw/bank.taler.net/-/ABDE123 + + +------------------------- +Low-level Reserve Actions +------------------------- + +The following actions are deprecated. They might not be supported +in newer wallets. + +.. code:: none + + 'taler://reserve-create/' reserve-pub + +.. code:: none + + 'taler://reserve-confirm/' query + +---------------------------- +Special URLs for fulfillment +---------------------------- + +The special `fulfillment-success` action can be used in a fulfillment URI to indicate success +with a message, without directing the user to a website. This is useful in applications that are not Web-based: + +When wallets encounter this URI in any other circumstance than going to a fulfillment URL, they must raise an error. + +Example: + +.. code:: none + + taler://fulfillment-success/Thank+you+for+donating+to+GNUnet + diff --git a/core/wireformats.rst b/core/wireformats.rst new file mode 100644 index 00000000..12d23630 --- /dev/null +++ b/core/wireformats.rst @@ -0,0 +1,70 @@ +.. _wireformats: + +Wire Transfer Methods +===================== + +A wire transfer is essential for the exchange to transfer funds into a merchant's +account upon a successful deposit (see :ref:`deposit request `). The +merchant has to include the necessary information for the exchange to initiate the +wire transfer. + +The information required for wire transfer depends on the method of wire transfer +used. Since the wire transfers differ for each region, we document here the +ones currently supported by the exchange. + +X-TALER-BANK +------------ + +The "x-taler-bank" wire format is used for testing and for integration with Taler's +simple "bank" system which in the future might be useful to setup a bank +for a local / regional currency or accounting system. Using the @code{x-taler-bank} +wire method in combination with the Taler's bank, it is thus possible to +fully test the Taler system without using "real" currencies. The URL +format for "x-taler-bank" is simple, in that it only specifies an account +number and the URL of the bank: + + * payto://x-taler-bank/BANK_URI/ACCOUNT_NUMBER + +The account number given must be a positive 53-bit integer. As with +any payto://-URI, additional fields may be present (after a ?), but +are not required. The BANK_URI may include a port number. If none is +given, @code{https} over port 443 is assumed. If a port number is +given, @code{http} over the given port is to be used. Note that this +means that you cannot run an x-taler-bank over @code{https} on a +non-canonical port. + +Note that a particular exchange is usually only supporting one +particular bank with the "x-taler-bank" wire format, so it is not +possible for a merchant with an account at a different bank to use +"x-taler-bank" to transfer funds across banks. After all, this is for +testing and not for real banking. + +The "x-taler-bank" method is implemented by the @code{taler_bank} plugin. + + +SEPA +---- + +The Single Euro Payments Area (SEPA) [#sepa]_ is a regulation for electronic +payments. Since its adoption in 2012, all of the banks in the Eurozone and some +banks in other countries adhere to this standard for sending and receiving +payments. Note that the currency of the transfer will (currently) always be *EUR*. In +case the receiving account is in a currency other than EURO, the receiving bank +may covert the amount into that currency; currency exchange charges may be +levied by the receiving bank. + +For the merchant to receive deposits through SEPA, the deposit request must +follow the payto:// specification for SEPA: + + * payto://sepa/IBAN + + +The implementation of the @code{ebics} plugin which is envisioned to +support the @code{sepa} method is currently incomplete. Specifically, +we need a working implementation of `libebics` which is a sub-project +trying to implement the EBICS [#ebics]_ standard. + +.. [#sepa] SEPA - Single Euro Payments Area: + http://www.ecb.europa.eu/paym/sepa/html/index.en.html +.. [#ebics] EBCIS - European Banking Computer Interface Standard + http://www.ebics.org/ diff --git a/exchange-db-generate.sh b/exchange-db-generate.sh new file mode 100755 index 00000000..b296e0c9 --- /dev/null +++ b/exchange-db-generate.sh @@ -0,0 +1,3 @@ +#!/bin/sh +taler-exchange-dbinit -r +java -jar schemaSpy_5.0.0.jar -t pgsql -db taler -o taler -host localhost -dp /usr/share/java/postgresql-jdbc3-9.2.jar -u grothoff -p test -s public -hq diff --git a/exchange-db.png b/exchange-db.png new file mode 100644 index 00000000..421e5941 Binary files /dev/null and b/exchange-db.png differ diff --git a/index.rst b/index.rst index 4ed74072..7ffc9bbb 100644 --- a/index.rst +++ b/index.rst @@ -43,9 +43,8 @@ In this document, we describe the REST-based APIs between the various components, internal architecture of key components, and how to get them installed. --------------------------------------- -Taler HTTP Core Protocol Specification --------------------------------------- +Documentation Overview +---------------------- The *Protocol Specification* defines the HTTP-based, predominantly RESTful interfaces between the core components of Taler. @@ -53,20 +52,12 @@ interfaces between the core components of Taler. .. toctree:: :maxdepth: 2 - api-common - api-error - api-exchange - api-merchant - api-auditor - api-bank - wireformats - taler-uri - ---------- -Licensing ---------- - -.. toctree:: - :maxdepth: 2 - + core/index + taler-exchange + merchant-manual + merchant-api + taler-bank + backoffice + onboarding global-licensing + diff --git a/merchant-api.rst b/merchant-api.rst new file mode 100644 index 00000000..cc4ede93 --- /dev/null +++ b/merchant-api.rst @@ -0,0 +1,1703 @@ +The GNU Taler Merchant API Tutorial +################################### + +Introduction +============ + +About GNU Taler +--------------- + +GNU Taler is an open protocol for an electronic payment system with a +free software reference implementation. GNU Taler offers secure, fast +and easy payment processing using well understood cryptographic +techniques. GNU Taler allows customers to remain anonymous, while +ensuring that merchants can be held accountable by governments. Hence, +GNU Taler is compatible with anti-money-laundering (AML) and +know-your-customer (KYC) regulation, as well as data protection +regulation (such as GDPR). + +About this tutorial +------------------- + +This tutorial addresses how to process payments using the GNU Taler +merchant Backend. This chapter explains some basic concepts. In the +second chapter, you will learn how to do basic payments. + +This version of the tutorial has examples for Python3. It uses the +requests library for HTTP requests. Versions for other +languages/environments are available as well. + +examples +git +If you want to look at some simple, running examples, check out these: + +- The `essay + merchant `__ + that sells single chapters of a book. + +- The `donation + page `__ + that accepts donations for software projects and gives donation + receipts. + +- The + `survey `__ + that gives users who answer a question a small reward. + +Architecture overview +--------------------- + +The Taler software stack for a merchant consists of the following main +components: + +- frontend + A frontend which interacts with the customer’s browser. The frontend + enables the customer to build a shopping cart and place an order. + Upon payment, it triggers the respective business logic to satisfy + the order. This component is not included with Taler, but rather + assumed to exist at the merchant. This tutorial describes how to + develop a Taler frontend. + +- backend + A Taler-specific payment backend which makes it easy for the frontend + to process financial transactions with Taler. For this tutorial, you + will use a public sandbox backend. For production use, you must + either set up your own backend or ask another person to do so for + you. + +The following image illustrates the various interactions of these key +components: + +|image0| + +The backend provides the cryptographic protocol support, stores +Taler-specific financial information and communicates with the GNU Taler +exchange over the Internet. The frontend accesses the backend via a +RESTful API. As a result, the frontend never has to directly communicate +with the exchange, and also does not deal with sensitive data. In +particular, the merchant’s signing keys and bank account information are +encapsulated within the Taler backend. + +Some functionality of the backend (the “public interface“) is also +exposed to the customer’s browser directly. In the HTTP API, all public +endpoints are prefixed with ``/public/``. + +Public Sandbox Backend and Authentication +----------------------------------------- + +sandbox +authorization +How the frontend authenticates to the Taler backend depends on the +configuration. See Taler Merchant Operating Manual. + +The public sandbox backend https://backend.demo.taler.net/ uses an API +key in the ``Authorization`` header. The value of this header must be +``ApiKey sandbox`` for the public sandbox backend. + +:: + + >>> import requests + >>> requests.get("https://backend.demo.taler.net", + ... headers={"Authorization": "ApiKey sandbox"}) + + +If an HTTP status code other than 200 is returned, something went wrong. +You should figure out what the problem is before continuing with this +tutorial. + +The sandbox backend https://backend.demo.taler.net/ uses ``KUDOS`` as an +imaginary currency. Coins denominated in ``KUDOS`` can be withdrawn from +https://bank.demo.taler.net/. + +Merchant Instances +------------------ + +instance +The same Taler merchant backend server can be used by multiple separate +merchants that are separate business entities. Each of these separate +business entities is called a *merchant instance*, and is identified by +an alphanumeric *instance id*. If the instance is omitted, the instance +id ``default`` is assumed. + +The following merchant instances are configured on +https://backend.demo.taler.net/: + +- ``GNUnet`` (The GNUnet project) + +- ``FSF`` (The Free Software Foundation) + +- ``Tor`` (The Tor Project) + +- ``default`` (Kudos Inc.) + +Note that these are fictional merchants used for our demonstrators and +not affiliated with or officially approved by the respective projects. + +.. _Accepting-a-Simple-Payment: + +Accepting a Simple Payment +========================== + +Creating an Order for a Payment +------------------------------- + +order +Payments in Taler revolve around an *order*, which is a machine-readable +description of the business transaction for which the payment is to be +made. Before accepting a Taler payment as a merchant you must create +such an order. + +This is done by posting a JSON object to the backend’s ``/order`` API +endpoint. At least the following fields must be given: + +- amount: The amount to be paid, as a string in the format + ``CURRENCY:DECIMAL_VALUE``, for example ``EUR:10`` for 10 Euros or + ``KUDOS:1.5`` for 1.5 KUDOS. + +- summary: A human-readable summary for what the payment is about. The + summary should be short enough to fit into titles, though no hard + limit is enforced. + +- fulfillment_url: A URL that will be displayed once the payment is + completed. For digital goods, this should be a page that displays the + product that was purchased. On successful payment, the wallet + automatically appends the ``order_id`` as a query parameter, as well + as the ``session_sig`` for session-bound payments (discussed later). + +Orders can have many more fields, see `The Taler Order +Format <#The-Taler-Order-Format>`__. + +After successfully ``POST``\ ing to ``/order``, an ``order_id`` will be +returned. Together with the merchant ``instance``, the order id uniquely +identifies the order within a merchant backend. + +:: + + >>> import requests + >>> order = dict(order=dict(amount="KUDOS:10", + ... summary="Donation", + ... fulfillment_url="https://example.com/thanks.html")) + >>> order_resp = requests.post("https://backend.demo.taler.net/order", json=order, + ... headers={"Authorization": "ApiKey sandbox"}) + + +The backend will fill in some details missing in the order, such as the +address of the merchant instance. The full details are called the +*contract terms*. contract terms + +Checking Payment Status and Prompting for Payment +------------------------------------------------- + +The status of a payment can be checked with the ``/check-payment`` +endpoint. If the payment is yet to be completed by the customer, +``/check-payment`` will give the frontend a URL (the +payment_redirect_url) that will trigger the customer’s wallet to execute +the payment. + +Note that the only way to obtain the payment_redirect_url is to check +the status of the payment, even if you know that the user did not pay +yet. + +:: + + >>> import requests + >>> r = requests.get("https://backend.demo.taler.net/check-payment", + ... params=dict(order_id=order_resp.json()["order_id"]), + ... headers={"Authorization": "ApiKey sandbox"}) + >>> print(r.json()) + +If the paid field in the response is ``true``, the other fields in the +response will be different. Once the payment was completed by the user, +the response will contain the following fields: + +- paid: Set to true. + +- contract_terms: The full contract terms of the order. + +- refunded: ``true`` if a (possibly partial) refund was granted for + this purchase. + +- refunded_amount: Amount that was refunded + +- last_session_id: Last session ID used by the customer’s wallet. See + `Session-Bound Payments <#Session_002dBound-Payments>`__. + +Once the frontend has confirmed that the payment was successful, it +usually needs to trigger the business logic for the merchant to fulfill +the merchant’s obligations under the contract. + +.. _Giving-Refunds: + +Giving Refunds +============== + +refunds +A refund in GNU Taler is a way to “undo” a payment. It needs to be +authorized by the merchant. Refunds can be for any fraction of the +original amount paid, but they cannot exceed the original payment. +Refunds are time-limited and can only happen while the exchange holds +funds for a particular payment in escrow. The time during which a refund +is possible can be controlled by setting the ``refund_deadline`` in an +order. The default value for this refund deadline is specified in the +configuration of the merchant’s backend. + +The frontend can instruct the merchant backend to authorize a refund by +``POST``\ ing to the ``/refund`` endpoint. + +The refund request JSON object has the following fields: + +- order_id: Identifies for which order a customer should be refunded. + +- instance: Merchant instance to use. + +- refund: Amount to be refunded. If a previous refund was authorized + for the same order, the new amount must be higher, otherwise the + operation has no effect. The value indicates the total amount to be + refunded, *not* an increase in the refund. + +- reason: Human-readable justification for the refund. The reason is + only used by the Back Office and is not exposed to the customer. + +If the request is successful (indicated by HTTP status code 200), the +response includes a ``refund_redirect_url``. The frontend must redirect +the customer’s browser to that URL to allow the refund to be processed +by the wallet. + +This code snipped illustrates giving a refund: + +:: + + >>> import requests + >>> refund_req = dict(order_id="2018.058.21.46.06-024C85K189H8P", + ... refund="KUDOS:10", + ... instance="default", + ... reason="Customer did not like the product") + >>> requests.post("https://backend.demo.taler.net/refund", json=refund_req, + ... headers={"Authorization": "ApiKey sandbox"}) + + +.. _Giving-Customers-Tips: + +Giving Customers Tips +===================== + +tips +GNU Taler allows Web sites to grant small amounts directly to the +visitor. The idea is that some sites may want incentivize actions such +as filling out a survey or trying a new feature. It is important to note +that tips are not enforceable for the visitor, as there is no contract. +It is simply a voluntary gesture of appreciation of the site to its +visitor. However, once a tip has been granted, the visitor obtains full +control over the funds provided by the site. + +The “merchant” backend of the site must be properly configured for +tipping, and sufficient funds must be made available for tipping See +Taler Merchant Operating Manual. + +To check if tipping is configured properly and if there are sufficient +funds available for tipping, query the ``/tip-query`` endpoint: + +:: + + >>> import requests + >>> requests.get("https://backend.demo.taler.net/tip-query?instance=default", + ... headers={"Authorization": "ApiKey sandbox"}) + + +authorize tip +To authorize a tip, ``POST`` to ``/tip-authorize``. The following fields +are recognized in the JSON request object: + +- amount: Amount that should be given to the visitor as a tip. + +- instance: Merchant instance that grants the tip (each instance may + have its own independend tipping funds configured). + +- justification: Description of why the tip was granted. Human-readable + text not exposed to the customer, but used by the Back Office. + +- next_url: The URL that the user’s browser should be redirected to by + the wallet, once the tip has been processed. + +The response from the backend contains a ``tip_redirect_url``. The +customer’s browser must be redirected to this URL for the wallet to pick +up the tip. pick up tip + +This code snipped illustrates giving a tip: + +:: + + >>> import requests + >>> tip_req = dict(amount="KUDOS:0.5", + ... instance="default", + ... justification="User filled out survey", + ... next_url="https://merchant.com/thanks.html") + >>> requests.post("https://backend.demo.taler.net/tip-authorize", json=tip_req, + ... headers={"Authorization": "ApiKey sandbox"}) + + +.. _Advanced-topics: + +Advanced topics +=============== + +.. _Detecting-the-Presence-of-the-Taler-Wallet: + +Detecting the Presence of the Taler Wallet +------------------------------------------ + +wallet +Taler offers ways to detect whether a user has the wallet installed in +their browser. This allows Web sites to adapt accordingly. Note that not +all platforms can do presence detection reliably. Some platforms might +have a Taler wallet installed as a separate App instead of using a Web +extension. In these cases, presence detection will fail. Thus, sites may +want to allow users to request Taler payments even if a wallet could not +be detected, especially for visitors using mobiles. + +Presence detection without JavaScript +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Presence detection without JavaScript is based on CSS classes. You can +hide or show elements selectively depending on whether the wallet is +detected or not. + +In order to work correctly, a special fallback stylesheet must be +included that will be used when the wallet is not present. The +stylesheet can be put into any file, but must be included via a ``link`` +tag with the ``id`` attribute set to ``taler-presence-stylesheet``. If a +wallet is present, it will “hijack” this stylesheet to change how +elements with the following classes are rendered: + +The following CSS classes can be used: + +``taler-installed-hide`` + A CSS rule will set the ``display`` property for this class to + ``none`` once the Taler wallet is installed and enabled. If the + wallet is not installed, ``display`` will be ``inherit``. + +``taler-installed-show`` + A CSS rule will set the ``display`` property for this class to + ``inherit`` once the Taler wallet is installed and enabled. If the + wallet is not installed, ``display`` will be ``none``. + +The following is a complete example: + +:: + + + + + Tutorial + + + +

+ No wallet found. +

+

+ Wallet found! +

+ + + +The ``taler-fallback.css`` is part of the Taler’s *web-common* +repository, available at +https://git.taler.net/web-common.git/tree/taler-fallback.css. You may +have to adjust the ``href`` attribute in the HTML code above to point to +the correct location of the ``taler-fallback.css`` file on your Web +site. + +Detection with JavaScript +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following functions are defined in the ``taler`` namespace of the +``taler-wallet-lib`` helper library available at +https://git.taler.net/web-common.git/tree/taler-wallet-lib.js. + +``onPresent(callback: () => void)`` + Adds a callback to be called when support for Taler payments is + detected. + +``onAbsent(callback: () => void)`` + Adds a callback to be called when support for Taler payments is + disabled. + +Note that the registered callbacks may be called more than once. This +may happen if a user disables or enables the wallet in the browser’s +extension settings while a shop’s frontend page is open. + +.. _Integration-with-the-Back-Office: + +Integration with the Back Office +-------------------------------- + +Taler ships a Back Office application as a stand-alone Web application. +The Back Office has its own documentation at +https://docs.taler.net/backoffice/html/manual.html. + +Developers wishing to tightly integrate back office support for +Taler-based payments into an existing back office application should +focus on the wire transfer tracking and transaction history sections of +the Taler Backend API specification at +https://docs.taler.net/api/api-merchant.html + +.. _Session_002dBound-Payments: + +Session-Bound Payments +---------------------- + +session +Sometimes checking if an order has been paid for is not enough. For +example, when selling access to online media, the publisher may want to +be paid for exactly the same product by each customer. Taler supports +this model by allowing the mechant to check whether the “payment +receipt” is available on the user’s current device. This prevents users +from easily sharing media access by transmitting a link to the +fulfillment page. Of course sophisticated users could share payment +receipts as well, but this is not as easy as sharing a link, and in this +case they are more likely to just share the media directly. + +To use this feature, the merchant must first assign the user’s current +browser an ephemeral ``session_id``, usually via a session cookie. When +executing or re-playing a payment, the wallet will receive an additional +signature (``session_sig``). This signature certifies that the wallet +showed a payment receipt for the respective order in the current +session. cookie + +Session-bound payments are triggerd by passing the ``session_id`` +parameter to the ``/check-payment`` endpoint. The wallet will then +redirect to the fulfillment page, but include an additional +``session_sig`` parameter. The frontend can query ``/check-payment`` +with both the ``session_id`` and the ``session_sig`` to verify that the +signature is correct. + +The last session ID that was successfuly used to prove that the payment +receipt is in the user’s wallet is also available as ``last_session_id`` +in the response to ``/check-payment``. + +.. _Product-Identification: + +Product Identification +---------------------- + +resource url +In some situations the user may have paid for some digital good, but the +frontend does not know the exact order ID, and thus cannot instruct the +wallet to reveil the existing payment receipt. This is common for simple +shops without a login system. In this case, the user would be prompted +for payment again, even though they already purchased the product. + +To allow the wallet to instead find the existing payment receipt, the +shop must use a unique fulfillment URL for each product. Then, the +frontend must provide an additional ``resource_url`` parameter to to +``/check-payment``. It should identify this unique fulfillment URL for +the product. The wallet will then check whether it has paid for a +contract with the same ``resource_url`` before, and if so replay the +previous payment. + +.. _The-Taler-Order-Format: + +The Taler Order Format +---------------------- + +contract +terms +order +A Taler order can specify many details about the payment. This section +describes each of the fields in depth. + +Financial amounts are always specified as a string in the format +``"CURRENCY:DECIMAL_VALUE"``. + +amount + amount + Specifies the total amount to be paid to the merchant by the + customer. + +max_fee + fees + maximum deposit fee + This is the maximum total amount of deposit fees that the merchant is + willing to pay. If the deposit fees for the coins exceed this amount, + the customer has to include it in the payment total. The fee is + specified using the same triplet used for amount. + +max_wire_fee + fees + maximum wire fee + Maximum wire fee accepted by the merchant (customer share to be + divided by the ’wire_fee_amortization’ factor, and further reduced if + deposit fees are below ’max_fee’). Default if missing is zero. + +wire_fee_amortization + fees + maximum fee amortization + Over how many customer transactions does the merchant expect to + amortize wire fees on average? If the exchange’s wire fee is above + ’max_wire_fee’, the difference is divided by this number to compute + the expected customer’s contribution to the wire fee. The customer’s + contribution may further be reduced by the difference between the + ’max_fee’ and the sum of the actual deposit fees. Optional, default + value if missing is 1. 0 and negative values are invalid and also + interpreted as 1. + +pay_url + pay_url + Which URL accepts payments. This is the URL where the wallet will + POST coins. + +fulfillment_url + fulfillment URL + Which URL should the wallet go to for obtaining the fulfillment, for + example the HTML or PDF of an article that was bought, or an order + tracking system for shipments, or a simple human-readable Web page + indicating the status of the contract. + +order_id + order ID + Alphanumeric identifier, freely definable by the merchant. Used by + the merchant to uniquely identify the transaction. + +summary + summary + Short, human-readable summary of the contract. To be used when + displaying the contract in just one line, for example in the + transaction history of the customer. + +timestamp + Time at which the offer was generated. + +pay_deadline + payment deadline + Timestamp of the time by which the merchant wants the exchange to + definitively wire the money due from this contract. Once this + deadline expires, the exchange will aggregate all deposits where the + contracts are past the refund_deadline and execute one large wire + payment for them. Amounts will be rounded down to the wire transfer + unit; if the total amount is still below the wire transfer unit, it + will not be disbursed. + +refund_deadline + refund deadline + Timestamp until which the merchant willing (and able) to give refunds + for the contract using Taler. Note that the Taler exchange will hold + the payment in escrow at least until this deadline. Until this time, + the merchant will be able to sign a message to trigger a refund to + the customer. After this time, it will no longer be possible to + refund the customer. Must be smaller than the pay_deadline. + +products + product description + Array of products that are being sold to the customer. Each entry + contains a tuple with the following values: + + description + Description of the product. + + quantity + Quantity of the items to be shipped. May specify a unit (``1 kg``) + or just the count. + + price + Price for quantity units of this product shipped to the given + delivery_location. Note that usually the sum of all of the prices + should add up to the total amount of the contract, but it may be + different due to discounts or because individual prices are + unavailable. + + product_id + Unique ID of the product in the merchant’s catalog. Can generally + be chosen freely as it only has meaning for the merchant, but + should be a number in the range :math:`[0,2^{51})`. + + taxes + Map of applicable taxes to be paid by the merchant. The label is + the name of the tax, i.e. VAT, sales tax or income tax, and the + value is the applicable tax amount. Note that arbitrary labels are + permitted, as long as they are used to identify the applicable tax + regime. Details may be specified by the regulator. This is used to + declare to the customer which taxes the merchant intends to pay, + and can be used by the customer as a receipt. The information is + also likely to be used by tax audits of the merchant. + + delivery_date + Time by which the product is to be delivered to the + delivery_location. + + delivery_location + This should give a label in the locations map, specifying where + the item is to be delivered. + + Values can be omitted if they are not applicable. For example, if a + purchase is about a bundle of products that have no individual prices + or product IDs, the product_id or price may not be specified in the + contract. Similarly, for virtual products delivered directly via the + fulfillment URI, there is no delivery location. + +merchant + address + This should give a label in the locations map, specifying where + the merchant is located. + + name + This should give a human-readable name for the merchant’s + business. + + jurisdiction + This should give a label in the locations map, specifying the + jurisdiction under which this contract is to be arbitrated. + +locations + location + Associative map of locations used in the contract. Labels for + locations in this map can be freely chosen and used whenever a + location is required in other parts of the contract. This way, if the + same location is required many times (such as the business address of + the customer or the merchant), it only needs to be listed (and + transmitted) once, and can otherwise be referred to via the label. A + non-exhaustive list of location attributes is the following: + + country + Name of the country for delivery, as found on a postal package, + i.e. “France”. + + state + Name of the state for delivery, as found on a postal package, i.e. + “NY”. + + region + Name of the region for delivery, as found on a postal package. + + province + Name of the province for delivery, as found on a postal package. + + city + Name of the city for delivery, as found on a postal package. + + ZIP code + ZIP code for delivery, as found on a postal package. + + street + Street name for delivery, as found on a postal package. + + street number + Street number (number of the house) for delivery, as found on a + postal package. + + name receiver name for delivery, either business or person name. + + Note that locations are not required to specify all of these fields, + and they is also allowed to have additional fields. Contract + renderers must render at least the fields listed above, and should + render fields that they do not understand as a key-value list. + +.. _GNU_002dLGPL: + +GNU-LGPL +======== + +license +LGPL +Version 2.1, February 1999 +:: + + Copyright © 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + [This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence the + version number 2.1.] + +**Preamble** + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public Licenses are +intended to guarantee your freedom to share and change free software—to +make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some +specially designated software—typically libraries—of the Free Software +Foundation and other authors who decide to use it. You can use it too, +but we suggest you first think carefully about whether this license or +the ordinary General Public License is the better strategy to use in any +particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish); that you receive source code or can get it if +you want it; that you can change the software and use pieces of it in +new free programs; and that you are informed that you can do these +things. + +To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for you +if you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or +for a fee, you must give the recipients all the rights that we gave you. +You must make sure that they, too, receive or can get the source code. +If you link other code with the library, you must provide complete +object files to the recipients, so that they can relink them with the +library after making changes to the library and recompiling it. And you +must show them these terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is +no warranty for the free library. Also, if the library is modified by +someone else and passed on, the recipients should know that what they +have is not the original version, so that the original author’s +reputation will not be affected by problems that might be introduced by +others. + +Finally, software patents pose a constant threat to the existence of any +free program. We wish to make sure that a company cannot effectively +restrict the users of a free program by obtaining a restrictive license +from a patent holder. Therefore, we insist that any patent license +obtained for a version of the library must be consistent with the full +freedom of use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License. This license, the GNU Lesser General Public +License, applies to certain designated libraries, and is quite different +from the ordinary General Public License. We use this license for +certain libraries in order to permit linking those libraries into +non-free programs. + +When a program is linked with a library, whether statically or using a +shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the entire +combination fits its criteria of freedom. The Lesser General Public +License permits more lax criteria for linking other code with the +library. + +We call this license the Lesser General Public License because it does +*Less* to protect the user’s freedom than the ordinary General Public +License. It also provides other free software developers Less of an +advantage over competing non-free programs. These disadvantages are the +reason we use the ordinary General Public License for many libraries. +However, the Lesser license provides advantages in certain special +circumstances. + +For example, on rare occasions, there may be a special need to encourage +the widest possible use of a certain library, so that it becomes a +de-facto standard. To achieve this, non-free programs must be allowed to +use the library. A more frequent case is that a free library does the +same job as widely used non-free libraries. In this case, there is +little to gain by limiting the free library to free software only, so we +use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of free +software. For example, permission to use the GNU C Library in non-free +programs enables many more people to use the whole GNU operating system, +as well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the +users’ freedom, it does ensure that the user of a program that is linked +with the Library has the freedom and the wherewithal to run that program +using a modified version of the Library. + +The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +“work based on the library” and a “work that uses the library”. The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + +**TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION** + +1. This License Agreement applies to any software library or other + program which contains a notice placed by the copyright holder or + other authorized party saying it may be distributed under the terms + of this Lesser General Public License (also called “this License”). + Each licensee is addressed as “you”. + + A “library” means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The “Library”, below, refers to any such software library or work + which has been distributed under these terms. A “work based on the + Library” means either the Library or any derivative work under + copyright law: that is to say, a work containing the Library or a + portion of it, either verbatim or with modifications and/or + translated straightforwardly into another language. (Hereinafter, + translation is included without limitation in the term + “modification”.) + + “Source code” for a work means the preferred form of the work for + making modifications to it. For a library, complete source code + means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to + control compilation and installation of the library. + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of + running a program using the Library is not restricted, and output + from such a program is covered only if its contents constitute a + work based on the Library (independent of the use of the Library in + a tool for writing it). Whether that is true depends on what the + Library does and what the program that uses the Library does. + +2. You may copy and distribute verbatim copies of the Library’s + complete source code as you receive it, in any medium, provided that + you conspicuously and appropriately publish on each copy an + appropriate copyright notice and disclaimer of warranty; keep intact + all the notices that refer to this License and to the absence of any + warranty; and distribute a copy of this License along with the + Library. + + You may charge a fee for the physical act of transferring a copy, + and you may at your option offer warranty protection in exchange for + a fee. + +3. You may modify your copy or copies of the Library or any portion of + it, thus forming a work based on the Library, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a. The modified work must itself be a software library. + + b. You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c. You must cause the whole of the work to be licensed at no charge + to all third parties under the terms of this License. + + d. If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure + that, in the event an application does not supply such function + or table, the facility still operates, and performs whatever part + of its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work + based on the Library, the distribution of the whole must be on the + terms of this License, whose permissions for other licensees extend + to the entire whole, and thus to each and every part regardless of + who wrote it. + + Thus, it is not the intent of this section to claim rights or + contest your rights to work written entirely by you; rather, the + intent is to exercise the right to control the distribution of + derivative or collective works based on the Library. + + In addition, mere aggregation of another work not based on the + Library with the Library (or with a work based on the Library) on a + volume of a storage or distribution medium does not bring the other + work under the scope of this License. + +4. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. To + do this, you must alter all the notices that refer to this License, + so that they refer to the ordinary GNU General Public License, + version 2, instead of to this License. (If a newer version than + version 2 of the ordinary GNU General Public License has appeared, + then you can specify that version instead if you wish.) Do not make + any other change in these notices. + + Once this change is made in a given copy, it is irreversible for + that copy, so the ordinary GNU General Public License applies to all + subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of the + Library into a program that is not a library. + +5. You may copy and distribute the Library (or a portion or derivative + of it, under Section 2) in object code or executable form under the + terms of Sections 1 and 2 above provided that you accompany it with + the complete corresponding machine-readable source code, which must + be distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange. + + If distribution of object code is made by offering access to copy + from a designated place, then offering equivalent access to copy the + source code from the same place satisfies the requirement to + distribute the source code, even though third parties are not + compelled to copy the source along with the object code. + +6. A program that contains no derivative of any portion of the Library, + but is designed to work with the Library by being compiled or linked + with it, is called a “work that uses the Library”. Such a work, in + isolation, is not a derivative work of the Library, and therefore + falls outside the scope of this License. + + However, linking a “work that uses the Library” with the Library + creates an executable that is a derivative of the Library (because + it contains portions of the Library), rather than a “work that uses + the library”. The executable is therefore covered by this License. + Section 6 states terms for distribution of such executables. + + When a “work that uses the Library” uses material from a header file + that is part of the Library, the object code for the work may be a + derivative work of the Library even though the source code is not. + Whether this is true is especially significant if the work can be + linked without the Library, or if the work is itself a library. The + threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data + structure layouts and accessors, and small macros and small inline + functions (ten lines or less in length), then the use of the object + file is unrestricted, regardless of whether it is legally a + derivative work. (Executables containing this object code plus + portions of the Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section + 6. Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + +7. As an exception to the Sections above, you may also combine or link + a “work that uses the Library” with the Library to produce a work + containing portions of the Library, and distribute that work under + terms of your choice, provided that the terms permit modification of + the work for the customer’s own use and reverse engineering for + debugging such modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered + by this License. You must supply a copy of this License. If the work + during execution displays copyright notices, you must include the + copyright notice for the Library among them, as well as a reference + directing the user to the copy of this License. Also, you must do + one of these things: + + a. Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable “work that + uses the Library”, as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in + the Library will not necessarily be able to recompile the + application to use the modified definitions.) + + b. Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user’s computer + system, rather than copying library functions into the + executable, and (2) will operate properly with a modified version + of the library, if the user installs one, as long as the modified + version is interface-compatible with the version that the work + was made with. + + c. Accompany the work with a written offer, valid for at least three + years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d. If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the + above specified materials from the same place. + + e. Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the “work that uses the + Library” must include any data and utility programs needed for + reproducing the executable from it. However, as a special exception, + the materials to be distributed need not include anything that is + normally distributed (in either source or binary form) with the + major components (compiler, kernel, and so on) of the operating + system on which the executable runs, unless that component itself + accompanies the executable. + + It may happen that this requirement contradicts the license + restrictions of other proprietary libraries that do not normally + accompany the operating system. Such a contradiction means you + cannot use both them and the Library together in an executable that + you distribute. + +8. You may place library facilities that are a work based on the + Library side-by-side in a single library together with other library + facilities not covered by this License, and distribute such a + combined library, provided that the separate distribution of the + work based on the Library and of the other library facilities is + otherwise permitted, and provided that you do these two things: + + a. Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities. + This must be distributed under the terms of the Sections above. + + b. Give prominent notice with the combined library of the fact that + part of it is a work based on the Library, and explaining where + to find the accompanying uncombined form of the same work. + +9. You may not copy, modify, sublicense, link with, or distribute the + Library except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense, link with, or distribute the + Library is void, and will automatically terminate your rights under + this License. However, parties who have received copies, or rights, + from you under this License will not have their licenses terminated + so long as such parties remain in full compliance. + +10. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify or + distribute the Library or its derivative works. These actions are + prohibited by law if you do not accept this License. Therefore, by + modifying or distributing the Library (or any work based on the + Library), you indicate your acceptance of this License to do so, and + all its terms and conditions for copying, distributing or modifying + the Library or works based on it. + +11. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the + Library subject to these terms and conditions. You may not impose + any further restrictions on the recipients’ exercise of the rights + granted herein. You are not responsible for enforcing compliance by + third parties with this License. + +12. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do + not excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under + this License and any other pertinent obligations, then as a + consequence you may not distribute the Library at all. For example, + if a patent license would not permit royalty-free redistribution of + the Library by all those who receive copies directly or indirectly + through you, then the only way you could satisfy both it and this + License would be to refrain entirely from distribution of the + Library. + + If any portion of this section is held invalid or unenforceable + under any particular circumstance, the balance of the section is + intended to apply, and the section as a whole is intended to apply + in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is + willing to distribute software through any other system and a + licensee cannot impose that choice. + + This section is intended to make thoroughly clear what is believed + to be a consequence of the rest of this License. + +13. If the distribution and/or use of the Library is restricted in + certain countries either by patents or by copyrighted interfaces, + the original copyright holder who places the Library under this + License may add an explicit geographical distribution limitation + excluding those countries, so that distribution is permitted only in + or among countries not thus excluded. In such case, this License + incorporates the limitation as if written in the body of this + License. + +14. The Free Software Foundation may publish revised and/or new versions + of the Lesser General Public License from time to time. Such new + versions will be similar in spirit to the present version, but may + differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the + Library specifies a version number of this License which applies to + it and “any later version”, you have the option of following the + terms and conditions either of that version or of any later version + published by the Free Software Foundation. If the Library does not + specify a license version number, you may choose any version ever + published by the Free Software Foundation. + +15. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + write to the author to ask for permission. For software which is + copyrighted by the Free Software Foundation, write to the Free + Software Foundation; we sometimes make exceptions for this. Our + decision will be guided by the two goals of preserving the free + status of all derivatives of our free software and of promoting the + sharing and reuse of software generally. + + NO WARRANTY +16. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT + WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER + PARTIES PROVIDE THE LIBRARY “AS IS” WITHOUT WARRANTY OF ANY KIND, + EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE + LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME + THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +17. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY + AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU + FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE + LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING + RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A + FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF + SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF + SUCH DAMAGES. + +**END OF TERMS AND CONDITIONS** + +**How to Apply These Terms to Your New Libraries** + +If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of +the ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should have +at least the “copyright” line and a pointer to where the full notice is +found. + +:: + + one line to give the library's name and an idea of what it does. + Copyright (C) year name of author + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or (at + your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a “copyright disclaimer” for the library, if +necessary. Here is a sample; alter the names: + +:: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the library + `Frob' (a library for tweaking knobs) written by James Random Hacker. + + signature of Ty Coon, 1 April 1990 + Ty Coon, President of Vice + +That’s all there is to it! + +.. _GNU_002dFDL: + +GNU-FDL +======= + +license +GNU Free Documentation License +Version 1.3, 3 November 2008 +:: + + Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. + http://fsf.org/ + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +1. PREAMBLE + + The purpose of this License is to make a manual, textbook, or other + functional and useful document free in the sense of freedom: to + assure everyone the effective freedom to copy and redistribute it, + with or without modifying it, either commercially or + noncommercially. Secondarily, this License preserves for the author + and publisher a way to get credit for their work, while not being + considered responsible for modifications made by others. + + This License is a kind of “copyleft”, which means that derivative + works of the document must themselves be free in the same sense. It + complements the GNU General Public License, which is a copyleft + license designed for free software. + + We have designed this License in order to use it for manuals for + free software, because free software needs free documentation: a + free program should come with manuals providing the same freedoms + that the software does. But this License is not limited to software + manuals; it can be used for any textual work, regardless of subject + matter or whether it is published as a printed book. We recommend + this License principally for works whose purpose is instruction or + reference. + +2. APPLICABILITY AND DEFINITIONS + + This License applies to any manual or other work, in any medium, + that contains a notice placed by the copyright holder saying it can + be distributed under the terms of this License. Such a notice grants + a world-wide, royalty-free license, unlimited in duration, to use + that work under the conditions stated herein. The “Document”, below, + refers to any such manual or work. Any member of the public is a + licensee, and is addressed as “you”. You accept the license if you + copy, modify or distribute the work in a way requiring permission + under copyright law. + + A “Modified Version” of the Document means any work containing the + Document or a portion of it, either copied verbatim, or with + modifications and/or translated into another language. + + A “Secondary Section” is a named appendix or a front-matter section + of the Document that deals exclusively with the relationship of the + publishers or authors of the Document to the Document’s overall + subject (or to related matters) and contains nothing that could fall + directly within that overall subject. (Thus, if the Document is in + part a textbook of mathematics, a Secondary Section may not explain + any mathematics.) The relationship could be a matter of historical + connection with the subject or with related matters, or of legal, + commercial, philosophical, ethical or political position regarding + them. + + The “Invariant Sections” are certain Secondary Sections whose titles + are designated, as being those of Invariant Sections, in the notice + that says that the Document is released under this License. If a + section does not fit the above definition of Secondary then it is + not allowed to be designated as Invariant. The Document may contain + zero Invariant Sections. If the Document does not identify any + Invariant Sections then there are none. + + The “Cover Texts” are certain short passages of text that are + listed, as Front-Cover Texts or Back-Cover Texts, in the notice that + says that the Document is released under this License. A Front-Cover + Text may be at most 5 words, and a Back-Cover Text may be at most 25 + words. + + A “Transparent” copy of the Document means a machine-readable copy, + represented in a format whose specification is available to the + general public, that is suitable for revising the document + straightforwardly with generic text editors or (for images composed + of pixels) generic paint programs or (for drawings) some widely + available drawing editor, and that is suitable for input to text + formatters or for automatic translation to a variety of formats + suitable for input to text formatters. A copy made in an otherwise + Transparent file format whose markup, or absence of markup, has been + arranged to thwart or discourage subsequent modification by readers + is not Transparent. An image format is not Transparent if used for + any substantial amount of text. A copy that is not “Transparent” is + called “Opaque”. + + Examples of suitable formats for Transparent copies include plain + ASCII without markup, Texinfo input format, LaTEX input format, SGML + or XML using a publicly available DTD, and standard-conforming + simple HTML, PostScript or PDF designed for human modification. + Examples of transparent image formats include PNG, XCF and JPG. + Opaque formats include proprietary formats that can be read and + edited only by proprietary word processors, SGML or XML for which + the DTD and/or processing tools are not generally available, and the + machine-generated HTML, PostScript or PDF produced by some word + processors for output purposes only. + + The “Title Page” means, for a printed book, the title page itself, + plus such following pages as are needed to hold, legibly, the + material this License requires to appear in the title page. For + works in formats which do not have any title page as such, “Title + Page” means the text near the most prominent appearance of the + work’s title, preceding the beginning of the body of the text. + + The “publisher” means any person or entity that distributes copies + of the Document to the public. + + A section “Entitled XYZ” means a named subunit of the Document whose + title either is precisely XYZ or contains XYZ in parentheses + following text that translates XYZ in another language. (Here XYZ + stands for a specific section name mentioned below, such as + “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) To + “Preserve the Title” of such a section when you modify the Document + means that it remains a section “Entitled XYZ” according to this + definition. + + The Document may include Warranty Disclaimers next to the notice + which states that this License applies to the Document. These + Warranty Disclaimers are considered to be included by reference in + this License, but only as regards disclaiming warranties: any other + implication that these Warranty Disclaimers may have is void and has + no effect on the meaning of this License. + +3. VERBATIM COPYING + + You may copy and distribute the Document in any medium, either + commercially or noncommercially, provided that this License, the + copyright notices, and the license notice saying this License + applies to the Document are reproduced in all copies, and that you + add no other conditions whatsoever to those of this License. You may + not use technical measures to obstruct or control the reading or + further copying of the copies you make or distribute. However, you + may accept compensation in exchange for copies. If you distribute a + large enough number of copies you must also follow the conditions in + section 3. + + You may also lend copies, under the same conditions stated above, + and you may publicly display copies. + +4. COPYING IN QUANTITY + + If you publish printed copies (or copies in media that commonly have + printed covers) of the Document, numbering more than 100, and the + Document’s license notice requires Cover Texts, you must enclose the + copies in covers that carry, clearly and legibly, all these Cover + Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on + the back cover. Both covers must also clearly and legibly identify + you as the publisher of these copies. The front cover must present + the full title with all words of the title equally prominent and + visible. You may add other material on the covers in addition. + Copying with changes limited to the covers, as long as they preserve + the title of the Document and satisfy these conditions, can be + treated as verbatim copying in other respects. + + If the required texts for either cover are too voluminous to fit + legibly, you should put the first ones listed (as many as fit + reasonably) on the actual cover, and continue the rest onto adjacent + pages. + + If you publish or distribute Opaque copies of the Document numbering + more than 100, you must either include a machine-readable + Transparent copy along with each Opaque copy, or state in or with + each Opaque copy a computer-network location from which the general + network-using public has access to download using public-standard + network protocols a complete Transparent copy of the Document, free + of added material. If you use the latter option, you must take + reasonably prudent steps, when you begin distribution of Opaque + copies in quantity, to ensure that this Transparent copy will remain + thus accessible at the stated location until at least one year after + the last time you distribute an Opaque copy (directly or through + your agents or retailers) of that edition to the public. + + It is requested, but not required, that you contact the authors of + the Document well before redistributing any large number of copies, + to give them a chance to provide you with an updated version of the + Document. + +5. MODIFICATIONS + + You may copy and distribute a Modified Version of the Document under + the conditions of sections 2 and 3 above, provided that you release + the Modified Version under precisely this License, with the Modified + Version filling the role of the Document, thus licensing + distribution and modification of the Modified Version to whoever + possesses a copy of it. In addition, you must do these things in the + Modified Version: + + A. Use in the Title Page (and on the covers, if any) a title + distinct from that of the Document, and from those of previous + versions (which should, if there were any, be listed in the + History section of the Document). You may use the same title as a + previous version if the original publisher of that version gives + permission. + + B. List on the Title Page, as authors, one or more persons or + entities responsible for authorship of the modifications in the + Modified Version, together with at least five of the principal + authors of the Document (all of its principal authors, if it has + fewer than five), unless they release you from this requirement. + + C. State on the Title page the name of the publisher of the Modified + Version, as the publisher. + + D. Preserve all the copyright notices of the Document. + + E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. + + F. Include, immediately after the copyright notices, a license + notice giving the public permission to use the Modified Version + under the terms of this License, in the form shown in the + Addendum below. + + G. Preserve in that license notice the full lists of Invariant + Sections and required Cover Texts given in the Document’s license + notice. + + H. Include an unaltered copy of this License. + + I. Preserve the section Entitled “History”, Preserve its Title, and + add to it an item stating at least the title, year, new authors, + and publisher of the Modified Version as given on the Title Page. + If there is no section Entitled “History” in the Document, create + one stating the title, year, authors, and publisher of the + Document as given on its Title Page, then add an item describing + the Modified Version as stated in the previous sentence. + + J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the “History” section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. + + K. For any section Entitled “Acknowledgements” or “Dedications”, + Preserve the Title of the section, and preserve in the section + all the substance and tone of each of the contributor + acknowledgements and/or dedications given therein. + + L. Preserve all the Invariant Sections of the Document, unaltered in + their text and in their titles. Section numbers or the equivalent + are not considered part of the section titles. + + M. Delete any section Entitled “Endorsements”. Such a section may + not be included in the Modified Version. + + N. Do not retitle any existing section to be Entitled “Endorsements” + or to conflict in title with any Invariant Section. + + O. Preserve any Warranty Disclaimers. + + If the Modified Version includes new front-matter sections or + appendices that qualify as Secondary Sections and contain no + material copied from the Document, you may at your option designate + some or all of these sections as invariant. To do this, add their + titles to the list of Invariant Sections in the Modified Version’s + license notice. These titles must be distinct from any other section + titles. + + You may add a section Entitled “Endorsements”, provided it contains + nothing but endorsements of your Modified Version by various + parties—for example, statements of peer review or that the text has + been approved by an organization as the authoritative definition of + a standard. + + You may add a passage of up to five words as a Front-Cover Text, and + a passage of up to 25 words as a Back-Cover Text, to the end of the + list of Cover Texts in the Modified Version. Only one passage of + Front-Cover Text and one of Back-Cover Text may be added by (or + through arrangements made by) any one entity. If the Document + already includes a cover text for the same cover, previously added + by you or by arrangement made by the same entity you are acting on + behalf of, you may not add another; but you may replace the old one, + on explicit permission from the previous publisher that added the + old one. + + The author(s) and publisher(s) of the Document do not by this + License give permission to use their names for publicity for or to + assert or imply endorsement of any Modified Version. + +6. COMBINING DOCUMENTS + + You may combine the Document with other documents released under + this License, under the terms defined in section 4 above for + modified versions, provided that you include in the combination all + of the Invariant Sections of all of the original documents, + unmodified, and list them all as Invariant Sections of your combined + work in its license notice, and that you preserve all their Warranty + Disclaimers. + + The combined work need only contain one copy of this License, and + multiple identical Invariant Sections may be replaced with a single + copy. If there are multiple Invariant Sections with the same name + but different contents, make the title of each such section unique + by adding at the end of it, in parentheses, the name of the original + author or publisher of that section if known, or else a unique + number. Make the same adjustment to the section titles in the list + of Invariant Sections in the license notice of the combined work. + + In the combination, you must combine any sections Entitled “History” + in the various original documents, forming one section Entitled + “History”; likewise combine any sections Entitled + “Acknowledgements”, and any sections Entitled “Dedications”. You + must delete all sections Entitled “Endorsements.” + +7. COLLECTIONS OF DOCUMENTS + + You may make a collection consisting of the Document and other + documents released under this License, and replace the individual + copies of this License in the various documents with a single copy + that is included in the collection, provided that you follow the + rules of this License for verbatim copying of each of the documents + in all other respects. + + You may extract a single document from such a collection, and + distribute it individually under this License, provided you insert a + copy of this License into the extracted document, and follow this + License in all other respects regarding verbatim copying of that + document. + +8. AGGREGATION WITH INDEPENDENT WORKS + + A compilation of the Document or its derivatives with other separate + and independent documents or works, in or on a volume of a storage + or distribution medium, is called an “aggregate” if the copyright + resulting from the compilation is not used to limit the legal rights + of the compilation’s users beyond what the individual works permit. + When the Document is included in an aggregate, this License does not + apply to the other works in the aggregate which are not themselves + derivative works of the Document. + + If the Cover Text requirement of section 3 is applicable to these + copies of the Document, then if the Document is less than one half + of the entire aggregate, the Document’s Cover Texts may be placed on + covers that bracket the Document within the aggregate, or the + electronic equivalent of covers if the Document is in electronic + form. Otherwise they must appear on printed covers that bracket the + whole aggregate. + +9. TRANSLATION + + Translation is considered a kind of modification, so you may + distribute translations of the Document under the terms of section + 4. Replacing Invariant Sections with translations requires special + permission from their copyright holders, but you may include + translations of some or all Invariant Sections in addition to the + original versions of these Invariant Sections. You may include a + translation of this License, and all the license notices in the + Document, and any Warranty Disclaimers, provided that you also + include the original English version of this License and the + original versions of those notices and disclaimers. In case of a + disagreement between the translation and the original version of + this License or a notice or disclaimer, the original version will + prevail. + + If a section in the Document is Entitled “Acknowledgements”, + “Dedications”, or “History”, the requirement (section 4) to Preserve + its Title (section 1) will typically require changing the actual + title. + +10. TERMINATION + + You may not copy, modify, sublicense, or distribute the Document + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense, or distribute it is void, and + will automatically terminate your rights under this License. + + However, if you cease all violation of this License, then your + license from a particular copyright holder is reinstated (a) + provisionally, unless and until the copyright holder explicitly and + finally terminates your license, and (b) permanently, if the + copyright holder fails to notify you of the violation by some + reasonable means prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is + reinstated permanently if the copyright holder notifies you of the + violation by some reasonable means, this is the first time you have + received notice of violation of this License (for any work) from + that copyright holder, and you cure the violation prior to 30 days + after your receipt of the notice. + + Termination of your rights under this section does not terminate the + licenses of parties who have received copies or rights from you + under this License. If your rights have been terminated and not + permanently reinstated, receipt of a copy of some or all of the same + material does not give you any rights to use it. + +11. FUTURE REVISIONS OF THIS LICENSE + + The Free Software Foundation may publish new, revised versions of + the GNU Free Documentation License from time to time. Such new + versions will be similar in spirit to the present version, but may + differ in detail to address new problems or concerns. See + http://www.gnu.org/copyleft/. + + Each version of the License is given a distinguishing version + number. If the Document specifies that a particular numbered version + of this License “or any later version” applies to it, you have the + option of following the terms and conditions either of that + specified version or of any later version that has been published + (not as a draft) by the Free Software Foundation. If the Document + does not specify a version number of this License, you may choose + any version ever published (not as a draft) by the Free Software + Foundation. If the Document specifies that a proxy can decide which + future versions of this License can be used, that proxy’s public + statement of acceptance of a version permanently authorizes you to + choose that version for the Document. + +12. RELICENSING + + “Massive Multiauthor Collaboration Site” (or “MMC Site”) means any + World Wide Web server that publishes copyrightable works and also + provides prominent facilities for anybody to edit those works. A + public wiki that anybody can edit is an example of such a server. A + “Massive Multiauthor Collaboration” (or “MMC”) contained in the site + means any set of copyrightable works thus published on the MMC site. + + “CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 + license published by Creative Commons Corporation, a not-for-profit + corporation with a principal place of business in San Francisco, + California, as well as future copyleft versions of that license + published by that same organization. + + “Incorporate” means to publish or republish a Document, in whole or + in part, as part of another Document. + + An MMC is “eligible for relicensing” if it is licensed under this + License, and if all works that were first published under this + License somewhere other than this MMC, and subsequently incorporated + in whole or in part into the MMC, (1) had no cover texts or + invariant sections, and (2) were thus incorporated prior to November + 1, 2008. + + The operator of an MMC Site may republish an MMC contained in the + site under CC-BY-SA on the same site at any time before August 1, + 2009, provided the MMC is eligible for relicensing. + +**ADDENDUM: How to use this License for your documents** + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and license +notices just after the title page: + +:: + + Copyright (C) year your name. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover + Texts. A copy of the license is included in the section entitled ``GNU + Free Documentation License''. + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the “with…Texts.” line with this: + +:: + + with the Invariant Sections being list their titles, with + the Front-Cover Texts being list, and with the Back-Cover Texts + being list. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of free +software license, such as the GNU General Public License, to permit +their use in free software. + +.. _Concept-Index: + +Concept Index +============= + +.. |image0| image:: arch-api.png + diff --git a/merchant-manual.rst b/merchant-manual.rst new file mode 100644 index 00000000..563a1e9f --- /dev/null +++ b/merchant-manual.rst @@ -0,0 +1,1228 @@ + + +This manual is for the GNU Taler merchant backend (version 0.5.0, 17 +August 2019), + +Copyright © 2016, 2017, 2019 Taler Systems SA + + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 or + any later version published by the Free Software Foundation; with no + Invariant Sections, with no Front-Cover Texts, and with no Back-Cover + Texts. A copy of the license is included in the section entitled “GNU + Free Documentation License”. + +The GNU Taler manual for Web shops +################################## + +This manual is for the GNU Taler merchant backend (version 0.5.0, 17 +August 2019), + +Copyright © 2016, 2017, 2019 Taler Systems SA + + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 or + any later version published by the Free Software Foundation; with no + Invariant Sections, with no Front-Cover Texts, and with no Back-Cover + Texts. A copy of the license is included in the section entitled “GNU + Free Documentation License”. + +Introduction +============ + +About GNU Taler +--------------- + +GNU Taler is an open protocol for an electronic payment system with a +free software reference implementation. GNU Taler offers secure, fast +and easy payment processing using well understood cryptographic +techniques. GNU Taler allows customers to remain anonymous, while +ensuring that merchants can be held accountable by governments. Hence, +GNU Taler is compatible with anti-money-laundering (AML) and +know-your-customer (KYC) regulation, as well as data protection +regulation (such as GDPR). + +GNU Taler is not yet production-ready, after following this manual you +will have a backend that can process payments in “KUDOS”, but not +regular currencies. This is not so much because of limitations in the +backend, but because we are not aware of a Taler exchange operator +offering regular currencies today. + +.. _About-this-manual: + +About this manual +----------------- + +This tutorial targets system administrators who want to install a GNU +Taler merchant *backend*. + +We expect some moderate familiarity with the compilation and +installation of free software packages. An understanding of cryptography +is not required. + +This first chapter of the tutorial will give a brief overview of the +overall Taler architecture, describing the environment in which the +Taler backend operates. The second chapter then explains how to install +the software, including key dependencies. The third chapter will explain +how to configure the backend, including in particular the configuration +of the bank account details of the merchant. + +The last chapter gives some additional information about advanced topics +which will be useful for system administrators but are not necessary for +operating a basic backend. + +.. _Architecture-overview: + +Architecture overview +--------------------- + +crypto-currency +KUDOS +Taler is a pure payment system, not a new crypto-currency. As such, it +operates in a traditional banking context. In particular, this means +that in order to receive funds via Taler, the merchant must have a +regular bank account, and payments can be executed in ordinary +currencies such as USD or EUR. For testing purposes, Taler uses a +special currency “KUDOS” and includes its own special bank. + +The Taler software stack for a merchant consists of four main +components: + +- frontend + A frontend which interacts with the customer’s browser. The frontend + enables the customer to build a shopping cart and place an order. + Upon payment, it triggers the respective business logic to satisfy + the order. This component is not included with Taler, but rather + assumed to exist at the merchant. This manual describes how to + integrate Taler with Web shop frontends. + +- back office + A back office application that enables the shop operators to view + customer orders, match them to financial transfers, and possibly + approve refunds if an order cannot be satisfied. This component is + again not included with Taler, but rather assumed to exist at the + merchant. This manual will describe how to integrate such a component + to handle payments managed by Taler. + +- backend + A Taler-specific payment backend which makes it easy for the frontend + to process financial transactions with Taler. The next two chapters + will describe how to install and configure this backend. + +- DBMS + Postgres + A DBMS which stores the transaction history for the Taler backend. + For now, the GNU Taler reference implemenation only supports + Postgres, but the code could be easily extended to support another + DBMS. + +The following image illustrates the various interactions of these key +components: + +:: + + Missing diagram image + +RESTful +Basically, the backend provides the cryptographic protocol support, +stores Taler-specific financial information in a DBMS and communicates +with the GNU Taler exchange over the Internet. The frontend accesses the +backend via a RESTful API. As a result, the frontend never has to +directly communicate with the exchange, and also does not deal with +sensitive data. In particular, the merchant’s signing keys and bank +account information is encapsulated within the Taler backend. + +Installation +============ + +This chapter describes how to install the GNU Taler merchant backend. + +Installing Taler using Docker +----------------------------- + +This section provides instructions for the merchant backend installation +using ‘Docker‘. + +For security reasons, we run Docker against a VirtualBox instance, so +the ``docker`` command should connect to a ``docker-machine`` instance +that uses the VirtualBox driver. + +Therefore, the needed tools are: “docker“, “docker-machine“, and +“docker-compose“. Please refer to Docker’s official [1]_ documentation +in order to get those components installed, as that is not in this +manual’s scope. + +Before starting to build the merchant’s image, make sure a +“docker-machine“ instance is up and running. + +Because all of the Docker source file are kept in our “deployment“ +repository, we start by checking out the ``git://taler.net/deployment`` +codebase: + +:: + + $ git clone git://taler.net/deployment + +Now we actually build the merchant’s image. From the same directory as +above: + +:: + + $ cd deployment/docker/merchant/ + $ docker-compose build + +If everything worked as expected, the merchant is ready to be launched. +From the same directory as the previous step: + +:: + + # Recall: the docker-machine should be up and running. + $ docker-compose up + +You should see some live logging from all the involved containers. At +this stage of development, you should also ignore some (harmless) error +message from postresql about already existing roles and databases. + +To test if everything worked as expected, it suffices to issue a simple +request to the merchant, as: + +:: + + $ curl http://$(docker-machine ip)/ + # A greeting message should be returned by the merchant. + +.. _Generic-instructions: + +Generic instructions +-------------------- + +This section provides generic instructions for the merchant backend +installation independent of any particular operating system. Operating +system specific instructions are provided in the following sections. You +should follow the operating system specific instructions if those are +available, and only consult the generic instructions if no +system-specific instructions are provided for your specific operating +system. + +.. _Installation-of-dependencies: + +Installation of dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following packages need to be installed before we can compile the +backend: + +- autoconf >= 2.69 + +- automake >= 1.14 + +- libtool >= 2.4 + +- autopoint >= 0.19 + +- libltdl >= 2.4 + +- libunistring >= 0.9.3 + +- libcurl >= 7.26 (or libgnurl >= 7.26) + +- GNU libmicrohttpd >= 0.9.39 + +- GNU libgcrypt >= 1.6 + +- libjansson >= 2.7 + +- Postgres >= 9.4, including libpq + +- libgnunetutil (from Git) + +- GNU Taler exchange (from Git) + +Except for the last two, these are available in most GNU/Linux +distributions and should just be installed using the respective package +manager. + +The following sections will provide detailed instructions for installing +the libgnunetutil and GNU Taler exchange dependencies. + +.. _Installing-libgnunetutil: + +Installing libgnunetutil +~~~~~~~~~~~~~~~~~~~~~~~~ + +GNUnet +Before you install libgnunetutil, you must download and install the +dependencies mentioned in the previous section, otherwise the build may +succeed but fail to export some of the tooling required by Taler. + +To download and install libgnunetutil, proceed as follows: + +:: + + $ git clone https://gnunet.org/git/gnunet/ + $ cd gnunet/ + $ ./bootstrap + $ ./configure [--prefix=GNUNETPFX] + $ # Each dependency can be fetched from non standard locations via + $ # the '--with-' option. See './configure --help'. + $ make + # make install + +If you did not specify a prefix, GNUnet will install to ``/usr/local``, +which requires you to run the last step as ``root``. + +.. _Installing-the-GNU-Taler-exchange: + +Installing the GNU Taler exchange +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +exchange +After installing GNUnet, you can download and install the exchange as +follows: + +:: + + $ git clone git://taler.net/exchange + $ cd exchange + $ ./bootstrap + $ ./configure [--prefix=EXCHANGEPFX] \ + [--with-gnunet=GNUNETPFX] + $ # Each dependency can be fetched from non standard locations via + $ # the '--with-' option. See './configure --help'. + $ make + # make install + +If you did not specify a prefix, the exchange will install to +``/usr/local``, which requires you to run the last step as ``root``. +Note that you have to specify ``--with-gnunet=/usr/local`` if you +installed GNUnet to ``/usr/local`` in the previous step. + +.. _Installing-the-GNU-Taler-merchant-backend: + +Installing the GNU Taler merchant backend +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +backend +The following steps assume all dependencies are installed. + +Use the following commands to download and install the merchant backend: + +:: + + $ git clone git://taler.net/merchant + $ cd merchant + $ ./bootstrap + $ ./configure [--prefix=PFX] \ + [--with-gnunet=GNUNETPFX] \ + [--with-exchange=EXCHANGEPFX] + $ # Each dependency can be fetched from non standard locations via + $ # the '--with-' option. See './configure --help'. + $ make + $ make install + +Note that you have to specify ``--with-exchange=/usr/local`` and/or +``--with-exchange=/usr/local`` if you installed the exchange and/or +GNUnet to ``/usr/local`` in the previous steps. + +.. _Installing-Taler-on-Debian-GNU_002fLinux: + +Installing Taler on Debian GNU/Linux +------------------------------------ + +Wheezy +Debian +Debian wheezy is too old and lacks most of the packages required. + +On Debian jessie, only GNU libmicrohttpd needs to be compiled from +source. To install dependencies on Debian jesse, run the following +commands: + +:: + + # apt-get install \ + autoconf \ + automake \ + autopoint \ + libtool \ + libltdl-dev \ + libunistring-dev \ + libcurl4-gnutls-dev \ + libgcrypt20-dev \ + libjansson-dev \ + libpq-dev \ + postgresql-9.4 + # wget https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-latest.tar.gz + # wget https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-latest.tar.gz.sig + # gpg -v libmicrohttpd-latest.tar.gz # Should show signed by 939E6BE1E29FC3CC + # tar xf libmicrohttpd-latest.tar.gz + # cd libmicrohttpd-0* + # ./configure + # make install + +For more recent versions of Debian, you should instead run: + +:: + + # apt-get install \ + autoconf \ + automake \ + autopoint \ + libtool \ + libltdl-dev \ + libunistring-dev \ + libcurl4-gnutls-dev \ + libgcrypt20-dev \ + libjansson-dev \ + libpq-dev \ + postgresql-9.5 \ + libmicrohttpd-dev + +For the rest of the installation, follow the generic installation +instructions starting with the installation of libgnunetutil. Note that +if you used the Debian wheezy instructions above, you need to pass +``--with-microhttpd=/usr/local/`` to all ``configure`` invocations. + +How to configure the merchant’s backend +======================================= + +taler-config +taler.conf +The installation already provides reasonable defaults for most of the +configuration options. However, some must be provided, in particular the +database account and bank account that the backend should use. By +default, the file ``$HOME/.config/taler.conf`` is where the Web shop +administrator specifies configuration values that augment or override +the defaults. The format of the configuration file is the well-known INI +file format. You can edit the file by hand, or use the ``taler-config`` +commands given as examples. For more information on ``taler-config``, +see `Using taler-config <#Using-taler_002dconfig>`__. + +.. _Backend-options: + +Backend options +--------------- + +The following table describes the options that commonly need to be +modified. Here, the notation ``[$section]/$option`` denotes the option +``$option`` under the section ``[$section]`` in the configuration file. + +Service address + The following option sets the transport layer address used by the + merchant backend: + + UNIX domain socket + TCP + :: + + [MERCHANT]/SERVE = TCP | UNIX + + If given, + + - ``TCP``, then we need to set the TCP port in ``[MERCHANT]/PORT`` + + - ``UNIX``, then we need to set the unix domain socket path and mode + in ``[MERCHANT]/UNIXPATH`` and ``[MERCHANT]/UNIXPATH_MODE``. The + latter takes the usual permission mask given as a number, e.g. 660 + for user/group read-write access. + + The frontend can then connect to the backend over HTTP using the + specified address. If frontend and backend run within the same + operating system, the use of a UNIX domain socket is recommended to + avoid accidentally exposing the backend to the network. + + port + To run the Taler backend on TCP port 8888, use: + + :: + + $ taler-config -s MERCHANT -o SERVE -V TCP + $ taler-config -s MERCHANT -o PORT -V 8888 + +Currency + Which currency the Web shop deals in, i.e. “EUR” or “USD”, is + specified using the option + + currency + KUDOS + :: + + [TALER]/CURRENCY + + For testing purposes, the currency MUST match “KUDOS” so that tests + will work with the Taler demonstration exchange at + https://exchange.demo.taler.net/: + + :: + + $ taler-config -s TALER -o CURRENCY -V KUDOS + +Database + DBMS + In principle is possible for the backend to support different DBMSs. + The option + + :: + + [MERCHANT]/DB + + specifies which DBMS is to be used. However, currently only the value + "postgres" is supported. This is also the default. + + In addition to selecting the DBMS software, the backend requires + DBMS-specific options to access the database. + + For postgres, you need to provide: + + :: + + [merchantdb-postgres]/config + + Postgres + This option specifies a postgres access path using the format + ``postgres:///$DBNAME``, where ``$DBNAME`` is the name of the + Postgres database you want to use. Suppose ``$USER`` is the name of + the user who will run the backend process. Then, you need to first + run + + :: + + $ sudu -u postgres createuser -d $USER + + as the Postgres database administrator (usually ``postgres``) to + grant ``$USER`` the ability to create new databases. Next, you should + as ``$USER`` run: + + :: + + $ createdb $DBNAME + + to create the backend’s database. Here, ``$DBNAME`` must match the + database name given in the configuration file. + + To configure the Taler backend to use this database, run: + + :: + + $ taler-config -s MERCHANTDB-postgres -o CONFIG \ + -V postgres:///$DBNAME + +Exchange + exchange + To add an exchange to the list of trusted payment service providers, + you create a section with a name that starts with “exchange-”. In + that section, the following options need to be configured: + + - The “url” option specifies the exchange’s base URL. For example, + to use the Taler demonstrator use: + + :: + + $ taler-config -s EXCHANGE-demo -o URL \ + -V https://exchange.demo.taler.net/ + + - master key + The “master_key” option specifies the exchange’s master public key + in base32 encoding. For the Taler demonstrator, use: + + :: + + $ taler-config -s EXCHANGE-demo -o master_key \ + -V CQQZ9DY3MZ1ARMN5K1VKDETS04Y2QCKMMCFHZSWJWWVN82BTTH00 + + Note that multiple exchanges can be added to the system by using + different tokens in place of ``demo`` in the example above. Note + that all of the exchanges must use the same currency. If you need + to support multiple currencies, you need to configure a backend + per currency. + +Instances + instance + The backend allows the user to run multiple instances of shops with + distinct business entities against a single backend. Each instance + uses its own bank accounts and key for signing contracts. It is + mandatory to configure a "default" instance. + + - The “KEYFILE” option specifies the file containing the instance’s + private signing key. For example, use: + + :: + + $ taler-config -s INSTANCE-default -o KEYFILE \ + -V '${TALER_CONFIG_HOME}/merchant/instace/default.key' + + - The “NAME” option specifies a human-readable name for the + instance. For example, use: + + :: + + $ taler-config -s INSTANCE-default -o NAME \ + -V 'Kudos Inc.' + + - The optional “TIP_EXCHANGE” and “TIP_EXCHANGE_PRIV_FILENAME” + options are discussed in Tipping visitors + +Accounts + wire format + In order to receive payments, the merchant backend needs to + communicate bank account details to the exchange. For this, the + configuration must include one or more sections named “ACCOUNT-name” + where ``name`` can be replaced by some human-readable word + identifying the account. For each section, the following options + should be provided: + + - The “URL” option specifies a ``payto://``-URL for the account of + the merchant. For example, use: + + :: + + $ taler-config -s ACCOUNT-bank -o NAME \ + -V 'payto://x-taler-bank/bank.demo.taler.net/4' + + - The “WIRE_RESPONSE” option specifies where Taler should store the + (salted) JSON encoding of the wire account. The file given will be + created if it does not exist. For example, use: + + :: + + $ taler-config -s ACCOUNT-bank -o WIRE_RESPONSE \ + -V '{$TALER_CONFIG_HOME}/merchant/bank.json' + + - The “PLUGIN” option specifies which wire plugin should be used for + this account. The plugin must support the wire method used by the + URL. For example, use: + + :: + + $ taler-config -s ACCOUNT-bank -o PLUGIN \ + -V taler_bank + + - For each ``instance`` that should use this account, you should set + ``HONOR_instance`` and ``ACTIVE_instance`` to YES. The first + option will cause the instance to accept payments to the account + (for existing contracts), while the second will cause the backend + to include the account as a possible option for new contracts. + + For example, use: + + :: + + $ taler-config -s ACCOUNT-bank -o HONOR_default \ + -V YES + $ taler-config -s ACCOUNT-bank -o ACTIVE_default \ + -V YES + + to use “account-bank” for the “default” instance. + + Depending on which PLUGIN you configured, you may additionally + specfiy authentication options to enable the plugin to use the + account. + + For example, with ``taler_bank`` plugin, use: + + :: + + $ taler-config -s ACCOUNT-bank -o TALER_BANK_AUTH_METHOD \ + -V basic + $ taler-config -s ACCOUNT-bank -o USERNAME \ + -V user42 + $ taler-config -s ACCOUNT-bank -o PASSWORD \ + -V pass42 + + Note that additional instances can be specified using different + tokens in the section name instead of ``default``. + +.. _Sample-backend-configuration: + +Sample backend configuration +---------------------------- + +configuration +The following is an example for a complete backend configuration: + +:: + + [TALER] + CURRENCY = KUDOS + + [MERCHANT] + SERVE = TCP + PORT = 8888 + DATABASE = postgres + + [MERCHANTDB-postgres] + CONFIG = postgres:///donations + + [INSTANCE-default] + KEYFILE = $DATADIR/key.priv + NAME = "Kudos Inc." + + [ACCOUNT-bank] + URL = payto://x-taler-bank/bank.demo.taler.net/4 + WIRE_RESPONSE = $DATADIR/bank.json + PLUGIN = taler_bank + HONOR_default = YES + ACTIVE_default = YES + TALER_BANK_AUTH_METHOD = basic + USERNAME = my_user + PASSWORD = 1234pass + + [EXCHANGE-trusted] + URL = https://exchange.demo.taler.net/ + MASTER_KEY = CQQZ9DY3MZ1ARMN5K1VKDETS04Y2QCKMMCFHZSWJWWVN82BTTH00 + CURRENCY = KUDOS + +Given the above configuration, the backend will use a database named +``donations`` within Postgres. + +The backend will deposit the coins it receives to the exchange at +https://exchange.demo.taler.net/, which has the master key +"CQQZ9DY3MZ1ARMN5K1VKDETS04Y2QCKMMCFHZSWJWWVN82BTTH00". + +Please note that ``doc/config.sh`` will walk you through all +configuration steps, showing how to invoke ``taler-config`` for each of +them. + +.. _Launching-the-backend: + +Launching the backend +--------------------- + +backend +taler-merchant-httpd +Assuming you have configured everything correctly, you can launch the +merchant backend using: + +:: + + $ taler-merchant-httpd + +When launched for the first time, this command will print a message +about generating your private key. If everything worked as expected, the +command + +:: + + $ curl http://localhost:8888/ + +should return the message + +:: + + Hello, I'm a merchant's Taler backend. This HTTP server is not for humans. + +Please note that your backend is right now likely globally reachable. +Production systems should be configured to bind to a UNIX domain socket +or properly restrict access to the port. + +.. _Testing: + +Testing +======= + +The tool ``taler-merchant-generate-payments`` can be used to test the +merchant backend installation. It implements all the payment’s steps in +a programmatically way, relying on the backend you give it as input. +Note that this tool gets installed along all the merchant backend’s +binaries. + +This tool gets configured by a config file, that must have the following +layout: + +:: + + [PAYMENTS-GENERATOR] + + # The exchange used during the test: make sure the merchant backend + # being tested accpets this exchange. + # If the sysadmin wants, she can also install a local exchange + # and test against it. + EXCHANGE = https://exchange.demo.taler.net/ + + # This value must indicate some URL where the backend + # to be tested is listening; it doesn't have to be the + # "official" one, though. + MERCHANT = http://localbackend/ + + # This value is used when the tool tries to withdraw coins, + # and must match the bank used by the exchange. If the test is + # done against the exchange at https://exchange.demo.taler.net/, + # then this value can be "https://bank.demo.taler.net/". + BANK = https://bank.demo.taler.net/ + + # The merchant instance in charge of serving the payment. + # Make sure this instance has a bank account at the same bank + # indicated by the 'bank' option above. + INSTANCE = default + + # The currency used during the test. Must match the one used + # by merchant backend and exchange. + CURRENCY = KUDOS + +Run the test in the following way: + +:: + + $ taler-merchant-generate-payments [-c config] [-e EURL] [-m MURL] + +The argument ``config`` given to ``-c`` points to the configuration file +and is optional – ``~/.config/taler.conf`` will be checked by default. +By default, the tool forks two processes: one for the merchant backend, +and one for the exchange. The option ``-e`` (``-m``) avoids any exchange +(merchant backend) fork, and just runs the generator against the +exchange (merchant backend) running at ``EURL`` (``MURL``). + +Please NOTE that the generator contains *hardcoded* values, as for +deposit fees of the coins it uses. In order to work against the used +exchange, those values MUST match the ones used by the exchange. + +The following example shows how the generator "sets" a deposit fee of +EUR:0.01 for the 5 EURO coin. + +:: + + // from /src/sample/generate_payments.c + { .oc = OC_PAY, + .label = "deposit-simple", + .expected_response_code = MHD_HTTP_OK, + .details.pay.contract_ref = "create-proposal-1", + .details.pay.coin_ref = "withdraw-coin-1", + .details.pay.amount_with_fee = concat_amount (currency, "5"), + .details.pay.amount_without_fee = concat_amount (currency, "4.99") }, + +The logic calculates the deposit fee according to the subtraction: +``amount_with_fee - amount_without_fee``. + +The following example shows a 5 EURO coin configuration - needed by the +used exchange - which is compatible with the hardcoded example above. + +:: + + [COIN_eur_5] + value = EUR:5 + duration_overlap = 5 minutes + duration_withdraw = 7 days + duration_spend = 2 years + duration_legal = 3 years + fee_withdraw = EUR:0.00 + fee_deposit = EUR:0.01 # important bit + fee_refresh = EUR:0.00 + fee_refund = EUR:0.00 + rsa_keysize = 1024 + +If the command terminates with no errors, then the merchant backend is +correctly installed. + +After this operation is done, the merchant database will have some dummy +data in it, so it may be convenient to clean all the tables; to this +purpose, issue the following command: + +:: + + $ taler-merchant-dbinit -r + + +Advanced topics +=============== + +Configuration format +-------------------- + +configuration +In Taler realm, any component obeys to the same pattern to get +configuration values. According to this pattern, once the component has +been installed, the installation deploys default values in +${prefix}/share/taler/config.d/, in .conf files. In order to override +these defaults, the user can write a custom .conf file and either pass +it to the component at execution time, or name it taler.conf and place +it under $HOME/.config/. + +A config file is a text file containing sections, and each section +contains its values. The right format follows: + +:: + + [section1] + value1 = string + value2 = 23 + + [section2] + value21 = string + value22 = /path22 + +Throughout any configuration file, it is possible to use ``$``-prefixed +variables, like ``$VAR``, especially when they represent filesystem +paths. It is also possible to provide defaults values for those +variables that are unset, by using the following syntax: +``${VAR:-default}``. However, there are two ways a user can set +``$``-prefixable variables: + +by defining them under a ``[paths]`` section, see example below, + +:: + + [paths] + TALER_DEPLOYMENT_SHARED = ${HOME}/shared-data + .. + [section-x] + path-x = ${TALER_DEPLOYMENT_SHARED}/x + +or by setting them in the environment: + +:: + + $ export VAR=/x + +The configuration loader will give precedence to variables set under +``[path]``, though. + +The utility ``taler-config``, which gets installed along with the +exchange, serves to get and set configuration values without directly +editing the .conf. The option ``-f`` is particularly useful to resolve +pathnames, when they use several levels of ``$``-expanded variables. See +``taler-config --help``. + +Note that, in this stage of development, the file +``$HOME/.config/taler.conf`` can contain sections for *all* the +component. For example, both an exchange and a bank can read values from +it. + +The repository ``git://taler.net/deployment`` contains examples of +configuration file used in our demos. See under ``deployment/config``. + + **Note** + + Expectably, some components will not work just by using default + values, as their work is often interdependent. For example, a + merchant needs to know an exchange URL, or a database name. + +.. _Using-taler_002dconfig: + +Using taler-config +------------------ + +taler-config +The tool ``taler-config`` can be used to extract or manipulate +configuration values; however, the configuration use the well-known INI +file format and can also be edited by hand. + +Run + +:: + + $ taler-config -s $SECTION + +to list all of the configuration values in section ``$SECTION``. + +Run + +:: + + $ taler-config -s $section -o $option + +to extract the respective configuration value for option ``$option`` in +section ``$section``. + +Finally, to change a setting, run + +:: + + $ taler-config -s $section -o $option -V $value + +to set the respective configuration value to ``$value``. Note that you +have to manually restart the Taler backend after you change the +configuration to make the new configuration go into effect. + +Some default options will use $-variables, such as ``$DATADIR`` within +their value. To expand the ``$DATADIR`` or other $-variables in the +configuration, pass the ``-f`` option to ``taler-config``. For example, +compare: + +:: + + $ taler-config -s ACCOUNT-bank \ + -o WIRE_RESPONSE + $ taler-config -f -s ACCOUNT-bank \ + -o WIRE_RESPONSE + +While the configuration file is typically located at +``$HOME/.config/taler.conf``, an alternative location can be specified +to ``taler-merchant-httpd`` and ``taler-config`` using the ``-c`` +option. + +.. _Merchant-key-management: + +Merchant key management +----------------------- + +merchant key +KEYFILE +The option “KEYFILE” in the section “INSTANCE-default” specifies the +path to the instance’s private key. You do not need to create a key +manually, the backend will generate it automatically if it is missing. +While generally unnecessary, it is possible to display the corresponding +public key using the ``gnunet-ecc`` command-line tool: + +:: + + $ gnunet-ecc -p \ + $(taler-config -f -s INSTANCE-default \ + -o KEYFILE) + +.. _SEPA-configuration: + +Using the SEPA wire transfer method +----------------------------------- + +SEPA +EBICS +The following is a sample configuration for the SEPA wire transfer +method: [2]_. + +Then, to configure the EBICS backend for SEPA payments in EUR, the +following configuration options need to be set: + +:: + + $ taler-config -s TALER -o CURRENCY -V EUR + $ taler-config -s ACCOUNT-e -o PLUGIN -V ebics + $ taler-config -s ACCOUNT-e -o URL \ + -V payto://sepa/XY00111122223333444455556666 + $ taler-config -s ACCOUNT-e -o WIRE_RESPONSE + -V '${DATADIR}/b.json' + +Please note that you will also have to configure an exchange and/or +auditors that support SEPA. However, we cannot explain how to do this +yet as such entities do not yet exist. Once such entities do exist, we +expect future versions of the Taler backend to ship with pre-configured +exchanges and auditors for common denominations. + +.. _Tipping-visitors: + +Tipping visitors +---------------- + +tipping +Taler can also be used to tip Web site visitors. For example, you may be +running an online survey, and you want to reward those people that have +dutifully completed the survey. If they have installed a Taler wallet, +you can provide them with a tip for their deeds. This section describes +how to setup the Taler merchant backend for tipping. + +There are four basic steps that must happen to tip a visitor. + +.. _Configure-a-reserve-and-exchange-for-tipping: + +Configure a reserve and exchange for tipping +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +gnunet-ecc +reserve key +To tip users, you first need to create a reserve. A reserve is a pool of +money held in escrow at the Taler exchange. This is the source of the +funds for the tips. Tipping will fail (resulting in disappointed +visitors) if you do not have enough funds in your reserve! + +First, we configure the backend. You need to enable tipping for each +instance separately, or you can use an instance only for tipping. To +configure the “default” instance for tipping, use the following +configuration: + +:: + + [INSTANCE-default] + # this is NOT the tip.priv + KEYFILE = signing_key.priv + # replace the URL with the URL of the exchange you will use + TIP_EXCHANGE = https://exchange:443/ + # here put the path to the file created with "gnunet-ecc -g1 tip.priv" + TIP_RESERVE_PRIV_FILENAME = tip.priv + +Note that the KEYFILE option should have already been present for the +instance. It has nothing to do with the “tip.priv” file we created +above, and you should probably use a different file here. + +Instead of manually editing the configuration, you could also run: + +:: + + $ taler-config -s INSTANCE-default \ + -o TIP_RESERVE_PRIV_FILENAME \ + -V tip.priv + $ taler-config -s INSTANCE-default \ + -o TIP_EXCHANGE \ + -V https://exchange:443/ + +Next, to create the ``TIP_RESERVE_PRIV_FILENAME`` file, use: + +:: + + $ gnunet-ecc -g 1 \ + $(taler-config -f -s INSTANCE-default \ + -o TIP-RESERVE_PRIV_FILENAME) + +This will create a file with the private key that will be used to +identify the reserve. You need to do this once for each instance that is +configured to tip. + +Now you can (re)start the backend with the new configuration. + +.. _Fund-the-reserve: + +Fund the reserve +~~~~~~~~~~~~~~~~ + +reserve +close +To fund the reserve, you must first extract the public key from +“tip.priv”: + +:: + + $ gnunet-ecc --print-public-key \ + $(taler-config -f -s INSTANCE-default \ + -o TIP-RESERVE_PRIV_FILENAME) + +In our example, the output for the public key is: + +:: + + QPE24X8PBX3BZ6E7GQ5VAVHV32FWTTCADR0TRQ183MSSJD2CHNEG + +You now need to make a wire transfer to the exchange’s bank account +using the public key as the wire transfer subject. The exchange’s bank +account details can be found in JSON format at +“https://exchange:443//wire/METHOD” where METHOD is the respective wire +method (i.e. “sepa”). Depending on the exchange’s operator, you may also +be able to find the bank details in a human-readable format on the main +page of the exchange. + +Make your wire transfer and (optionally) check at +“https://exchange:443/reserve/status/reserve_pub=QPE24X...” whether your +transfer has arrived at the exchange. + +Once the funds have arrived, you can start to use the reserve for +tipping. + +Note that an exchange will typically close a reserve after four weeks, +wiring all remaining funds back to the sender’s account. Thus, you +should plan to wire funds corresponding to a campaign of about two weeks +to the exchange initially. If your campaign runs longer, you should wire +further funds to the reserve every other week to prevent it from +expiring. + +.. _Authorize-a-tip: + +Authorize a tip +~~~~~~~~~~~~~~~ + +When your frontend has reached the point where a client is supposed to +receive a tip, it needs to first authorize the tip. For this, the +frontend must use the “/tip-authorize” API of the backend. To authorize +a tip, the frontend has to provide the following information in the body +of the POST request: + +- The amount of the tip + +- The justification (only used internally for the back-office) + +- The URL where the wallet should navigate next after the tip was + processed + +- The tip-pickup URL (see next section) + +In response to this request, the backend will return a tip token, an +expiration time and the exchange URL. The expiration time will indicate +how long the tip is valid (when the reserve expires). The tip token is +an opaque string that contains all the information needed by the wallet +to process the tip. The frontend must send this tip token to the browser +in a special “402 Payment Required” response inside the ``X-Taler-Tip`` +header. + +The frontend should handle errors returned by the backend, such as +missconfigured instances or a lack of remaining funds for tipping. + +.. _Picking-up-of-the-tip: + +Picking up of the tip +~~~~~~~~~~~~~~~~~~~~~ + +The wallet will POST a JSON object to the shop’s “/tip-pickup” handler. +The frontend must then forward this request to the backend. The response +generated by the backend can then be forwarded directly to the wallet. + +.. _Generate-payments: + +Generate payments +----------------- + +testing database +The merchant codebase offers the ``taler-merchant-benchmark`` tool to +populate the database with fake payments. This tool is in charge of +starting a merchant, exchange, and bank processes, and provide them all +the input to accomplish payments. Note that each component will use its +own configuration (as they would do in production). + +The tool takes all of the values it needs from the command line, with +some of them being mandatory. Among those, we have: + +- ``--currency=K`` Use currency *K*, for example to craft coins to + withdraw. + +- ``--bank-url=URL`` Assume that the bank is serving under the base URL + *URL*. This option is only actually used by the tool to check if the + bank was well launched. + +- ``--merchant-url=URL`` Reach the merchant through *URL*, for + downloading contracts and sending payments. + +The tool then comes with two operation modes: *ordinary*, and *corner*. +The first just executes normal payments, meaning that it uses the +default instance and make sure that all payments get aggregated. The +second gives the chance to leave some payments unaggregated, and also to +use merchant instances other than the default (which is, actually, the +one used by default by the tool). + +Note: the abilty of driving the aggregation policy is useful for testing +the backoffice facility. + +Any subcommand is also equipped with the canonical ``--help`` option, so +feel free to issue the following command in order to explore all the +possibilities. For example: + +:: + + $ taler-merchant-benchmark corner --help + +will show all the options offered by the *corner* mode. Among the most +interesting, there are: + +- ``--two-coins=TC`` This option instructs the tool to perform *TC* + many payments that use two coins, because normally only one coin is + spent per payment. + +- ``--unaggregated-number=UN`` This option instructs the tool to + perform *UN* (one coin) payments that will be left unaggregated. + +- ``--alt-instance=AI`` This option instructs the tool to perform + payments using the merchant instance *AI* (instead of the *default* + instance) + +As for the ``ordinary`` subcommand, it is worth explaining the following +options: + +- ``--payments-number=PN`` Instructs the tool to perform *PN* payments. + +- ``--tracks-number=TN`` Instructs the tool to perform *TN* tracking + operations. Note that the **total** amount of operations will be two + times *TN*, since "one" tracking operation accounts for + ``/track/transaction`` and ``/track/transfer``. This command should + only be used to see if the operation ends without problems, as no + actual measurement of performance is provided (despite of the + ’benchmark’ work used in the tool’s name). + +.. [1] + https://docs.docker.com/ + +.. [2] + Supporting SEPA is still work in progress; the backend will accept + this configuration, but the exchange will not work with SEPA today. diff --git a/onboarding.rst b/onboarding.rst new file mode 100644 index 00000000..b2fc829b --- /dev/null +++ b/onboarding.rst @@ -0,0 +1,386 @@ +Developer Onboarding Manual +########################### + + +Taler installation +================== + +Users serving Taler. +-------------------- + +On Gv.Taler.Net, there are four users that are set up to serve Taler on +the internet: + +- ``taler-test``: serves ``*.test.taler.net`` and gets automatically + built by Buildbot. + +- ``taler-internal``: serves ``*.int.taler.net``, and does *NOT* get + automatically built. + +The following two users are *NEVER* automatically built, and they both +serve ``*.demo.taler.net``. At any given time, only one is active and +serves the HTTP requests from the outside; the other one can so be +compiled without any downtime. If the compilation succeeds, the inactive +user can be switched to become active (see next section), and viceversa. + +- ``demo-blue`` + +- ``demo-green`` + +Compile and switch color. +------------------------- + +If the setup is already bootstrapped, then it should only be needed to +login as ’demo-X’ (with X being the inactive color); and then: + +:: + + $ source activate + $ taler-deployment-build + +and then switch the color by logging in as the *demo* user, and switch +the color with the following command: + +:: + + $ taler-deployment-switch-demo-X + +Full bootstrap. +--------------- + +In order to bootstrap a Taler installation under a empty home directory, +do: + +:: + + $ cd $HOME + $ git clone git://git.taler.net/deployment + +Then run the bootstrap script that will download all the repositories. + +:: + + $ ./deployment/bootstrap-taler + + # will make all the services serve *..taler.net + # + # Currently at Gv.Taler.Net, only 'demo' / 'test' / 'int' have + # DNS and certs configured. + +If successful, then activate the new environment with: + +:: + + source activate + +Compile and install all the components. + +:: + + $ taler-deployment-build + +Create the global configuration file. + +:: + + $ taler-deployment-config-generate + +Create (only) the folders where all the data needed by Taler will be +copied into (keys / JSONs with wire details / ..) + +:: + + $ taler-deployment-hier + +Create all the keys. + +:: + + $ taler-deployment-keyup + +Sign the ``/wire`` response for the exchange. + +:: + + $ taler-deployment-sign + +.. + + **Note** + + If the DB schema of merchant/exchange/auditor changed, at this point + it MIGHT be necessary to reset all the tables. To this regard, + consider running one of the following commands: + + :: + + # To reset the merchant DB. + $ taler-merchant-dbinit -r + + # To reset the exchange DB. + $ taler-exchange-dbinit -r + + # To reset the exchange DB. + $ taler-auditor-dbinit -r + +If all the steps succeeded, then it should be possible to launch all the +services. Give: + +:: + + $ taler-deployment-start + + # or restart, if you want to kill old processes and + # start new ones. + $ taler-deployment-restart + +Verify that all services are up and running: + +:: + + $ taler-deployment-arm -I + $ tail logs/-.log + +How to upgrade the code. +------------------------ + +Some repositories, especially the ones from the released components, +have a *stable* branch, that keeps older and more stable code. +Therefore, upon each release we must rebase those stable branches on the +master. + +The following commands do that: + +:: + + $ cd $REPO + + $ git pull origin master stable + $ git checkout stable + + # option a: resolve conflicts resulting from hotfixes + $ git rebase master + $ ... + + # option b: force stable to master + $ git update-ref refs/heads/stable master + + $ git push # possibly with --force + + # continue development + $ git checkout master + +.. _Testing-components: + +Testing components +================== + +This chapter is a VERY ABSTRACT description of how testing is +implemented in Taler, and in NO WAY wants to substitute the reading of +the actual source code by the user. + +In Taler, a test case is a array of ``struct TALER_TESTING_Command``, +informally referred to as ``CMD``, that is iteratively executed by the +testing interpreter. This latter is transparently initiated by the +testing library. + +However, the developer does not have to defined CMDs manually, but +rather call the proper constructor provided by the library. For example, +if a CMD is supposed to test feature ``x``, then the library would +provide the ``TALER_TESTING_cmd_x ()`` constructor for it. Obviously, +each constructor has its own particular arguments that make sense to +test ``x``, and all constructor are thoroughly commented within the +source code. + +Internally, each CMD has two methods: ``run ()`` and ``cleanup ()``. The +former contains the main logic to test feature ``x``, whereas the latter +cleans the memory up after execution. + +In a test life, each CMD needs some internal state, made by values it +keeps in memory. Often, the test has to *share* those values with other +CMDs: for example, CMD1 may create some key material and CMD2 needs this +key material to encrypt data. + +The offering of internal values from CMD1 to CMD2 is made by *traits*. A +trait is a ``struct TALER_TESTING_Trait``, and each CMD contains a array +of traits, that it offers via the public trait interface to other +commands. The definition and filling of such array happens transparently +to the test developer. + +For example, the following example shows how CMD2 takes an amount object +offered by CMD1 via the trait interface. + +Note: the main interpreter and the most part of CMDs and traits are +hosted inside the exchange codebase, but nothing prevents the developer +from implementing new CMDs and traits within other codebases. + +:: + + /* Withouth loss of generality, let's consider the + * following logic to exist inside the run() method of CMD1 */ + .. + + struct TALER_Amount *a; + /** + * the second argument (0) points to the first amount object offered, + * in case multiple are available. + */ + if (GNUNET_OK != TALER_TESTING_get_trait_amount_obj (cmd2, 0, &a)) + return GNUNET_SYSERR; + ... + + use(a); /* 'a' points straight into the internal state of CMD2 */ + +In the Taler realm, there is also the possibility to alter the behaviour +of supposedly well-behaved components. This is needed when, for example, +we want the exchange to return some corrupted signature in order to +check if the merchant backend detects it. + +This alteration is accomplished by another service called *twister*. The +twister acts as a proxy between service A and B, and can be programmed +to tamper with the data exchanged by A and B. + +Please refer to the Twister codebase (under the ``test`` directory) in +order to see how to configure it. + +.. _Releases: + +Releases +======== + +Release Process and Checklists +------------------------------ + +This document describes the process for releasing a new version of the +various Taler components to the official GNU mirrors. + +The following components are published on the GNU mirrors + +- taler-exchange (exchange.git) + +- taler-merchant (merchant.git) + +- talerdonations (donations.git) + +- talerblog (blog.git) + +- taler-bank (bank.git) + +- taler-wallet-webex (wallet-webex.git) + +Tagging +------- + +Tag releases with an **annotated** commit, like + +:: + + git tag -a v0.1.0 -m "Official release v0.1.0" + git push origin v0.1.0 + +Database for tests +------------------ + +For tests in the exchange and merchant to run, make sure that a database +*talercheck* is accessible by *$USER*. Otherwise tests involving the +database logic are skipped. + +Exchange, merchant +------------------ + +Set the version in ``configure.ac``. The commit being tagged should be +the change of the version. + +For the exchange test cases to pass, ``make install`` must be run first. +Without it, test cases will fail because plugins can’t be located. + +:: + + ./bootstrap + ./configure # add required options for your system + make dist + tar -xf taler-$COMPONENT-$VERSION.tar.gz + cd taler-$COMPONENT-$VERSION + make install check + +Wallet WebExtension +------------------- + +The version of the wallet is in *manifest.json*. The ``version_name`` +should be adjusted, and *version* should be increased independently on +every upload to the WebStore. + +:: + + ./configure + make dist + +Upload to GNU mirrors +--------------------- + +See +*https://www.gnu.org/prep/maintain/maintain.html#Automated-FTP-Uploads* + +Directive file: + +:: + + version: 1.2 + directory: taler + filename: taler-exchange-0.1.0.tar.gz + +Upload the files in **binary mode** to the ftp servers. + +.. _Code: + +Code +==== + +Taler code is versioned via Git. For those users without write access, +all the codebases are found at the following URL: + +:: + + git://git.taler.net/ + +A complete list of all the existing repositories is currently found at +``https://git.taler.net/``. Note: ```` must NOT have the +``.git`` extension. + +.. _Bugtracking: + +Bugtracking +=========== + +Bug tracking is done with Mantis (https://www.mantisbt.org/). All the +bugs are then showed and managed at ``https://bugs.gnunet.org/``, under +the "Taler" project. A registration on the Web site is needed in order +to use the bug tracker. + +.. _Continuous-integration: + +Continuous integration +====================== + +CI is done with Buildbot (https://buildbot.net/), and builds are +triggered by the means of Git hooks. The results are published at +``https://buildbot.wild.gv.taler.net/``. + +In order to avoid downtimes, CI uses a "blue/green" deployment +technique. In detail, there are two users building code on the system, +the "green" and the "blue" user; and at any given time, one is running +Taler services and the other one is either building the code or waiting +for that. + +There is also the possibility to trigger builds manually, but this is +only reserved to "admin" users. + +.. _Code-coverage: + +Code coverage +============= + +Code coverage is done with the Gcov / Lcov +(http://ltp.sourceforge.net/coverage/lcov.php) combo, and it is run +\*nightly\* (once a day) by a Buildbot worker. The coverage results are +then published at ``https://lcov.taler.net/``. diff --git a/taler-bank.rst b/taler-bank.rst new file mode 100644 index 00000000..c85e0aa4 --- /dev/null +++ b/taler-bank.rst @@ -0,0 +1,190 @@ +The GNU Taler bank manual +######################### + +Introduction +============ + +About GNU Taler +--------------- + +GNU Taler is an open protocol for an electronic payment system with a +free software reference implementation. GNU Taler offers secure, fast +and easy payment processing using well understood cryptographic +techniques. GNU Taler allows customers to remain anonymous, while +ensuring that merchants can be held accountable by governments. Hence, +GNU Taler is compatible with anti-money-laundering (AML) and +know-your-customer (KYC) regulation, as well as data protection +regulation (such as GDPR). + +About this manual +----------------- + +This manual documents how the demonstrator bank interoperates with the +other GNU Taler components. The demonstrator bank implements a simple +closed banking system for the purpose of illustrating how GNU Taler +works in the Taler demo. It could also be used as a starting point for a +local/regional currency. Finally, “real” banks might use it as a +reference implementation for a tight integration with the GNU Taler +wallet. + +.. _Reference: + +Reference +========= + +.. _Bank_002dWallet-interaction: + +Bank-Wallet interaction +----------------------- + +The HTTP status code ``202 Accepted`` can be used by the bank website to +trigger operations in the user agent. The operation is determined by the +``X-Taler-Operation`` header. The following operations are understood: + +``create-reserve`` + Ask the Taler wallet to create a reserve and call back the bank with + the reserve public key. The following headers are mandatory: + + - ``X-Taler-Callback-Url``: URL that the wallet will visit when the + reserve was created and the user has selected an exchange. + + - ``X-Taler-Wt-Types``: JSON-encoded array of wire transfer types + that this bank supports. + + - ``X-Taler-Amount``: The amount that will be transferred to the + reserve. + + - ``X-Taler-Sender-Wire``: JSON-encoded wire account details of the + sender, that is the user that is currently logged in with the bank + and creates the reserve. + + The following header is optional: + + - ``X-Taler-Suggested-Exchange``: Exchange that the bank recommends + the customer to use. Note that this is a suggestion and can be + ignored by the wallet or changed by the user. + + On successful reserve creation, the wallet will navigate to the + callback URL (effectively requesting it with a GET) with the + following additional request parameters: + + - ``exchange``: The URL of the exchange selected by the user + + - ``wire_details``: The wire details of the exchange. + + - ``reserve_pub``: The reserve public key that the bank should + transmit to the exchange when transmitting the funds. + +``confirm-reserve`` + To secure the operation, the (demo) bank then shows a "CAPTCHA page" + – a real bank would instead show some PIN entry dialog or similar + security method – where the customer can finally prove she their + identity and thereby confirm the withdraw operation to the bank. + + Afterwards, the bank needs to confirm to the wallet that the user + completed the required steps to transfer funds to an exchange to + establish the reserve identified by the ``X-Taler-Reserve-Pub`` + header. + + This does not guarantee that the reserve is already created at the + exchange (since the actual money transfer might be executed + asynchronously), but it informs that wallet that it can start polling + for the reserve. + +.. _Bank_002dExchange-interaction: + +Bank-Exchange interaction +------------------------- + +The interaction between a bank and the exchange happens in two +situations: when a wallet withdraws coins, and when the exchange pays a +merchant. + +Withdraw +~~~~~~~~ + +Once a withdrawal operation with the wallet has been confirmed, the the +bank must wire transfer the withdrawn amount from the customer account +to the exchange’s. After this operation is done, the exchange needs to +be informed so that it will create the reserve. + +For the moment, the bank will use the exchange’s ``/admin/add/incoming`` +API, providing those arguments it got along the ``X-Taler-Callback-Url`` +URL. (In the future, the exchange will poll for this information.) +However, the bank will define two additional values for this API: +``execution_date`` (a operation’s timestamp), and ``transfer_details`` +(just a "seed" to make unique the operation). See +https://docs.taler.net/api/api-exchange.html#administrative-api-bank-transactions. + +The polling mechanism is possbile thanks to the ``/history`` API +provided by the bank. The exchange will periodically use this API to see +if it has received new wire transfers; upon receiving a new wire +transfer, the exchange will automatically create a reserve and allow the +money sender to withdraw. + +``GET /history`` + Ask the bank to return a list of money transactions related to a + caller’s bank account. + + - ``auth`` a string indicating the authentication method to use; + only ``"basic"`` value is accepted so far. The username and + password credentials have to be sent along the HTTP request + headers. Namely, the bank will look for the following two headers: + ``X-Taler-Bank-Username`` and ``X-Taler-Bank-Password``, which + will contain those plain text credentials. + + - ``delta`` returns the first ``N`` records younger (older) than + ``start`` if ``+N`` (``-N``) is specified. + + - ``start`` according to delta, only those records with row id + strictly greater (lesser) than start will be returned. This + argument is optional; if not given, delta youngest records will be + returned. + + - ``direction`` optional argument taking values debit or credit, + according to the caller willing to receive both incoming and + outgoing, only outgoing, or only incoming records + + - ``account_number`` optional argument indicating the bank account + number whose history is to be returned. If not given, then the + history of the calling user will be returned + +Exchange pays merchant +~~~~~~~~~~~~~~~~~~~~~~ + +To allow the exchange to send payments to a merchant, the bank exposes +the ``/admin/add/incoming`` API to exchanges. + +``POST /admin/add/incoming`` + Ask the bank to transfer money from the caller’s account to the + receiver’s. + + - ``auth`` a string indicating the authentication method to use; + only ``"basic"`` value is accepted so far. The username and + password credentials have to be sent along the HTTP request + headers. Namely, the bank will look for the following two headers: + ``X-Taler-Bank-Username`` and ``X-Taler-Bank-Password``, which + will contain those plain text credentials. + + - ``amount`` a JSON object complying to the Taler amounts layout. + Namely, this object must contain the following fields: ``value`` + (number), ``fraction`` (number), and ``currency`` (string). + + - ``exchange_url`` a string indicating the calling exchange base + URL. The bank will use this value to define wire transfers subject + lines. + + - ``wtid`` a alphanumeric string that uniquely identifies this + transfer at the exchange database. The bank will use this value + too to define wire transfers subject lines. Namely, subject lines + will have the following format: ``'wtid exchange_url'``. + + - ``debit_account`` number indicating the exchange bank account. + NOTE: this field is currently ignored, as the bank can retrieve + the exchange account number from the login credentials. However, + in future release, an exchange could have multiple account at the + same bank, thereby it will have the chance to specify any of them + in this field. + + - ``credit_account`` bank account number that will receive the + transfer. Tipically the merchant account number. diff --git a/taler-exchange.rst b/taler-exchange.rst new file mode 100644 index 00000000..363a8f98 --- /dev/null +++ b/taler-exchange.rst @@ -0,0 +1,869 @@ +The GNU Taler Exchange Operator Manual +###################################### + +Introduction +============ + +This manual is an early draft that still needs significant editing work +to become readable. + +About GNU Taler +--------------- + +GNU Taler is an open protocol for an electronic payment system with a +free software reference implementation. GNU Taler offers secure, fast +and easy payment processing using well understood cryptographic +techniques. GNU Taler allows customers to remain anonymous, while +ensuring that merchants can be held accountable by governments. Hence, +GNU Taler is compatible with anti-money-laundering (AML) and +know-your-customer (KYC) regulation, as well as data protection +regulation (such as GDPR). + +GNU Taler is not yet production-ready, after following this manual you +will have a backend that can process payments in “KUDOS”, but not +regular currencies. This is not so much because of limitations in the +backend, but because we are not aware of a Taler exchange operator +offering regular currencies today. + +About this manual +----------------- + +This tutorial targets system administrators who want to install and +operate a GNU Taler exchange. + +Organizational prerequisites +---------------------------- + +Operating a GNU Taler exchange means that you are operating a payment +service provider, which means that you will most likely need a bank +license and/or follow applicable financial regulation. + +GNU Taler payment service providers generally need to ensure high +availability and have *really* good backups (synchronous replication, +asynchronous remote replication, off-site backup, 24/7 monitoring, +etc.). [1]_ This manual will not cover these aspects of operating a +payment service provider. + +We will assume that you can operate a (high-availability, +high-assurance) Postgres database. Furthermore, we expect some moderate +familiarity with the compilation and installation of free software +packages. You need to understand the cryptographic concepts of private +and public keys and must be able to protect private keys stored in files +on disk. An exchange uses an *offline* master key as well as *online* +keys. You are advised to secure your private master key and any copies +on encrypted, always-offline computers. Again, we assume that you are +familiar with good best practices in operational security, including +securing key material. [2]_ + +Architecture overview +--------------------- + +Taler is a pure payment system, not a new crypto-currency. As such, it +operates in a traditional banking context. In particular, this means +that in order to receive funds via Taler, the merchant must have a +regular bank account, and payments can be executed in ordinary +currencies such as USD or EUR. Similarly, the Taler exchange must +interact with a bank. The bank of the exchange holds the exchange’s +funds in an escrow account. + +When customers wire money to the escrow account, the bank notifies the +exchange about the incoming wire transfers. The exchange then creates a +*reserve* based on the subject of the wire transfer. The wallet which +knows the secret key matching the wire transfer subject can then +withdraw coins from the reserve, thereby draining it. The liability of +the exchange against the reserve is thereby converted into a liability +against digital coins issued by the exchange. When the customer later +spends the coins at a merchant, and the merchant *deposits* the coins at +the exchange, the exchange first *aggregates* the amount from multiple +deposits from the same merchant and then instructs its bank to make a +wire transfer to the merchant, thereby fulfilling its obligation and +eliminating the liability. The exchange charges *fees* for some or all +of its operations to cover costs and possibly make a profit. + +*Auditors* are third parties, for example financial regulators, that +verify that the exchange operates correctly. The same software is also +used to calculate the exchange’s profits, risk and liabilities by the +accountants of the exchange. + +The Taler software stack for an exchange consists of the following +components: + +- HTTP frontend + The HTTP frontend interacts with Taler wallets and merchant backends. + It is used to withdraw coins, deposit coins, refresh coins, issue + refunds, map wire transfers to Taler transactions, inquire about the + exchange’s bank account details, signing keys and fee structure. The + binary is the ``taler-exchange-httpd``. + +- Aggregator + The aggregator combines multiple deposits made by the same merchant + and (eventually) triggers wire transfers for the aggregate amount. + The merchant can control how quickly wire transfers are made. The + exchange may be charge a fee per wire transfer to discourage + excessively frequent transfers. The binary is the + ``taler-exchange-aggregator``. + +- Auditor + The auditor verifies that the transactions performed by the exchange + were done properly. It checks the various signatures, totals up the + amounts and alerts the operator to any inconsistencies. It also + computes the expected bank balance, revenue and risk exposure of the + exchange operator. The main binary is the ``taler-auditor``. + +- Wire plugin + A wire plugin enables the HTTP frontend to talk to the bank. Its role + is to allow the exchange to validate bank addresses (i.e. IBAN + numbers), for the aggregator to execute wire transfers and for the + auditor to query bank transaction histories. Wire plugins are + *plugins* as there can be many different implementations to deal with + different banking standards. Wire plugins are automatically located + and used by the exchange, aggregator and auditor. + +- DBMS + Postgres + The exchange requires a DBMS to stores the transaction history for + the Taler exchange and aggregator, and a (typically separate) DBMS + for the Taler auditor. For now, the GNU Taler reference implemenation + only supports Postgres, but the code could be easily extended to + support another DBMS. + +Installation +============ + +Please install the following packages before proceeding with the +exchange compilation. + +- GNU autoconf >= 2.69 + +- GNU automake >= 1.14 + +- GNU libtool >= 2.4 + +- GNU autopoint >= 0.19 + +- GNU libltdl >= 2.4 + +- GNU libunistring >= 0.9.3 + +- libcurl >= 7.26 (or libgnurl >= 7.26) + +- GNU libmicrohttpd >= 0.9.59 + +- GNU libgcrypt >= 1.6 + +- libjansson >= 2.7 + +- Postgres >= 9.6, including libpq + +- libgnunetutil (from Git) + +- GNU Taler exchange (from Git) + +Except for the last two, these are available in most GNU/Linux +distributions and should just be installed using the respective package +manager. + +The following instructions will show how to install libgnunetutil and +the GNU Taler exchange. + +Before you install libgnunetutil, you must download and install the +dependencies mentioned above, otherwise the build may succeed but fail +to export some of the tooling required by Taler. + +To download and install libgnunetutil, proceed as follows: + +:: + + $ git clone https://git.gnunet.org/gnunet/ + $ cd gnunet/ + $ ./bootstrap + $ ./configure [--prefix=GNUNETPFX] + $ # Each dependency can be fetched from non standard locations via + $ # the '--with-' option. See './configure --help'. + $ make + # make install + +If you did not specify a prefix, GNUnet will install to ``/usr/local``, +which requires you to run the last step as ``root``. + +To download and install the GNU Taler exchange, proceeds as follows: + +:: + + $ git clone git://git.taler.net/exchange + $ cd exchange + $ ./bootstrap + $ ./configure [--prefix=EXCHANGEPFX] \ + [--with-gnunet=GNUNETPFX] + $ # Each dependency can be fetched from non standard locations via + $ # the '--with-' option. See './configure --help'. + $ make + # make install + +If you did not specify a prefix, the exchange will install to +``/usr/local``, which requires you to run the last step as ``root``. +Note that you have to specify ``--with-gnunet=/usr/local`` if you +installed GNUnet to ``/usr/local`` in the previous step. + +Configuration +============= + +This chapter provides an overview of the exchange configuration. Or at +least eventually will do so, for now it is a somewhat wild description +of some of the options. + +Configuration format +-------------------- + +configuration +In Taler realm, any component obeys to the same pattern to get +configuration values. According to this pattern, once the component has +been installed, the installation deploys default values in +${prefix}/share/taler/config.d/, in .conf files. In order to override +these defaults, the user can write a custom .conf file and either pass +it to the component at execution time, or name it taler.conf and place +it under $HOME/.config/. + +A config file is a text file containing sections, and each section +contains its values. The right format follows: + +:: + + [section1] + value1 = string + value2 = 23 + + [section2] + value21 = string + value22 = /path22 + +Throughout any configuration file, it is possible to use ``$``-prefixed +variables, like ``$VAR``, especially when they represent filesystem +paths. It is also possible to provide defaults values for those +variables that are unset, by using the following syntax: +``${VAR:-default}``. However, there are two ways a user can set +``$``-prefixable variables: + +by defining them under a ``[paths]`` section, see example below, + +:: + + [paths] + TALER_DEPLOYMENT_SHARED = ${HOME}/shared-data + .. + [section-x] + path-x = ${TALER_DEPLOYMENT_SHARED}/x + +or by setting them in the environment: + +:: + + $ export VAR=/x + +The configuration loader will give precedence to variables set under +``[path]``, though. + +The utility ``taler-config``, which gets installed along with the +exchange, serves to get and set configuration values without directly +editing the .conf. The option ``-f`` is particularly useful to resolve +pathnames, when they use several levels of ``$``-expanded variables. See +``taler-config --help``. + +Note that, in this stage of development, the file +``$HOME/.config/taler.conf`` can contain sections for *all* the +component. For example, both an exchange and a bank can read values from +it. + +The repository ``git://taler.net/deployment`` contains examples of +configuration file used in our demos. See under ``deployment/config``. + + **Note** + + Expectably, some components will not work just by using default + values, as their work is often interdependent. For example, a + merchant needs to know an exchange URL, or a database name. + +.. _Using-taler_002dconfig-exchange: + +Using taler-config +------------------ + +The tool ``taler-config`` can be used to extract or manipulate +configuration values; however, the configuration use the well-known INI +file format and can also be edited by hand. + +Run + +:: + + $ taler-config -s $SECTION + +to list all of the configuration values in section ``$SECTION``. + +Run + +:: + + $ taler-config -s $section -o $option + +to extract the respective configuration value for option ``$option`` in +section ``$section``. + +Finally, to change a setting, run + +:: + + $ taler-config -s $section -o $option -V $value + +to set the respective configuration value to ``$value``. Note that you +have to manually restart the Taler backend after you change the +configuration to make the new configuration go into effect. + +Some default options will use $-variables, such as ``$DATADIR`` within +their value. To expand the ``$DATADIR`` or other $-variables in the +configuration, pass the ``-f`` option to ``taler-config``. For example, +compare: + +:: + + $ taler-config -s ACCOUNT-bank \ + -o WIRE_RESPONSE + $ taler-config -f -s ACCOUNT-bank \ + -o WIRE_RESPONSE + +While the configuration file is typically located at +``$HOME/.config/taler.conf``, an alternative location can be specified +to ``taler-merchant-httpd`` and ``taler-config`` using the ``-c`` +option. + +.. _Keying: + +Keying +------ + +The exchange works with three types of keys: + +- master key + +- sign keys + +- denomination keys (see section Coins) + +- MASTER_PRIV_FILE: Path to the exchange’s master private file. + +- MASTER_PUBLIC_KEY: Must specify the exchange’s master public key. + +.. _Serving: + +Serving +------- + +The exchange can serve HTTP over both TCP and UNIX domain socket. + +The following values are to be configured in the section [exchange]: + +- serve: must be set to tcp to serve HTTP over TCP, or unix to serve + HTTP over a UNIX domain socket + +- port: Set to the TCP port to listen on if serve Is tcp. + +- unixpath: set to the UNIX domain socket path to listen on if serve Is + unix + +- unixpath_mode: number giving the mode with the access permission MASK + for the unixpath (i.e. 660 = rw-rw—-). + +.. _Currency: + +Currency +-------- + +The exchange supports only one currency. This data is set under the +respective option currency in section [taler]. + +.. _Bank-account: + +Bank account +------------ + +To configure a bank account in Taler, we need to furnish four pieces of +information: + +- The ``payto://`` URL of the bank account, which uniquely idenfies the + account. Examples for such URLs include + ``payto://sepa/CH9300762011623852957`` for a bank account in the + single European payment area (SEPA) or + ``payto://x-taler-bank/localhost:8080/2`` for the 2nd bank account a + the Taler bank demonstrator running at ``localhost`` on port 8080. + The first part of the URL following ``payto://`` (“sepa” or + “x-taler-bank”) is called the wire method. + +- A matching wire plugin that implements a protocol to interact with + the banking system. For example, the EBICS plugin can be used for + SEPA transfers, or the “taler-bank” plugin can interact with the + Taler bank demonstrator. A wire plugin only supports one particular + wire method. Thus, you must make sure to pick a plugin that supports + the wire method used in the URL. + +- A file containing the signed JSON-encoded bank account details for + the /wire API. This is necessary as Taler supports offline signing + for bank accounts for additional security. + +- Finally, the plugin needs to be provided resources for authentication + to the respective banking service. The format in which the + authentication information must be provided depends on the wire + plugin. + +You can configure multiple accounts for an exchange by creating sections +starting with “account-” for the section name. You can ENABLE for each +account whether it should be used, and for what (incoming or outgoing +wire transfers): + +:: + + [account-1] + URL = "payto://sepa/CH9300762011623852957" + WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json + + # Currently, only the 'taler_bank' plugin is implemented. + PLUGIN = + + # Use for exchange-aggregator (outgoing transfers) + ENABLE_DEBIT = YES + # Use for exchange-wirewatch (and listed in /wire) + ENABLE_CREDIT = YES + + # Authentication options for the chosen plugin go here. + # (Next sections have examples of authentication mechanisms) + +The command line tool taler-exchange-wire is used to create the +``account-1.json`` file. For example, the utility may be invoked as +follows to create all of the WIRE_RESPONSE files (in the locations +specified by the configuration): + +:: + + $ taler-exchange-wire + +The generated file will be echoed by the exchange when serving +/wire [3]_ requests. + +.. _Wire-plugin-_0060_0060taler_005fbank_0027_0027: + +Wire plugin “taler_bank” +~~~~~~~~~~~~~~~~~~~~~~~~ + +x-taler-bank +taler_bank plugin +The ``taler_bank`` plugin implements the wire method “x-taler-bank”. + +The format of the ``payto://`` URL is +``payto://x-taler-bank/HOSTNAME[:PORT]``. + +For basic authentication, the ``taler_bank`` plugin only supports simple +password-based authentication. For this, the configuration must contain +the “USERNAME” and “PASSWORD” of the respective account at the bank. + +:: + + [account-1] + + # Bank account details here.. + # .. + + # Authentication options for the taler_bank plugin below: + + TALER_BANK_AUTH_METHOD = basic + USERNAME = exchange + PASSWORD = super-secure + +.. _Wire-plugin-_0060_0060ebics_0027_0027: + +Wire plugin “ebics” +~~~~~~~~~~~~~~~~~~~ + +The “ebics” wire plugin is not fully implemented and today does not +support actual wire transfers. + + **Note** + + The rationale behind having multiple bank accounts is that the + exchange operator, as a security measure, may want to instruct the + bank that the incoming bank account is only supposed to *receive* + money. + +.. _Wire-fee-structure: + +Wire fee structure +~~~~~~~~~~~~~~~~~~ + +wire fee +fee +For each wire method (“sepa” or “x-taler-wire”, but not per plugin!) the +exchange configuration must specify applicable wire fees. This is done +in configuration sections of the format ``fees-METHOD``. There are two +types of fees, simple wire fees and closing fees. Wire fees apply +whenever the aggregator transfers funds to a merchant. Closing fees +apply whenever the exchange closes a reserve (sending back funds to the +customer). The fees must be constant for a full year, which is specified +as part of the name of the option. + +:: + + [fees-iban] + WIRE-FEE-2018 = EUR:0.01 + WIRE-FEE-2019 = EUR:0.01 + CLOSING-FEE-2018 = EUR:0.01 + CLOSING-FEE-2019 = EUR:0.01 + + [fees-x-taler-bank] + WIRE-FEE-2018 = KUDOS:0.01 + WIRE-FEE-2019 = KUDOS:0.01 + CLOSING-FEE-2018 = KUDOS:0.01 + CLOSING-FEE-2019 = KUDOS:0.01 + +.. _Database: + +Database +-------- + +The option db under section [exchange] gets the DB backend’s name the +exchange is going to use. So far, only db = postgres is supported. After +choosing the backend, it is mandatory to supply the connection string +(namely, the database name). This is possible in two ways: + +- via an environment variable: TALER_EXCHANGEDB_POSTGRES_CONFIG. + +- via configuration option CONFIG, under section [exchangedb-BACKEND]. + For example, the demo exchange is configured as follows: + +:: + + [exchange] + ... + DB = postgres + ... + + [exchangedb-postgres] + CONFIG = postgres:///talerdemo + +.. _Coins-denomination-keys: + +Coins (denomination keys) +------------------------- + +Sections specifying denomination (coin) information start with ``coin_``. +By convention, the name continues with "$CURRENCY_[$SUBUNIT]_$VALUE", +i.e. ``[coin_eur_ct_10]`` for a 10 cent piece. However, only the ``coin_`` +prefix is mandatory. Each ``coin_``-section must then have the following +options: + +- value: How much is the coin worth, the format is + CURRENCY:VALUE.FRACTION. For example, a 10 cent piece is "EUR:0.10". + +- duration_withdraw: How long can a coin of this type be withdrawn? + This limits the losses incurred by the exchange when a denomination + key is compromised. + +- duration_overlap: What is the overlap of the withdrawal timespan for + this coin type? + +- duration_spend: How long is a coin of the given type valid? Smaller + values result in lower storage costs for the exchange. + +- fee_withdraw: What does it cost to withdraw this coin? Specified + using the same format as value. + +- fee_deposit: What does it cost to deposit this coin? Specified using + the same format as value. + +- fee_refresh: What does it cost to refresh this coin? Specified using + the same format as value. + +- rsa_keysize: How many bits should the RSA modulus (product of the two + primes) have for this type of coin. + +.. _Keys-duration: + +Keys duration +------------- + +Both signkeys and denom keys have a starting date. The option +lookahead_provide, under section [exchange], is such that only keys +whose starting date is younger than lookahead_provide will be issued by +the exchange. + +signkeys. The option lookahead_sign is such that, being t the time when +taler-exchange-keyup is run, taler-exchange-keyup will generate n +signkeys, where t + (n \* signkey_duration) = t + lookahead_sign. In +other words, we generate a number of keys which is sufficient to cover a +period of lookahead_sign. As for the starting date, the first generated +key will get a starting time of t, and the j-th key will get a starting +time of x + signkey_duration, where x is the starting time of the +(j-1)-th key. + +denom keys. The option lookahead_sign is such that, being t the time +when taler-exchange-keyup is run, taler-exchange-keyup will generate n +denom keys for each denomination, where t + (n \* duration_withdraw) = t ++ lookahead_sign. In other words, for each denomination, we generate a +number of keys which is sufficient to cover a period of lookahead_sign. +As for the starting date, the first generated key will get a starting +time of t, and the j-th key will get a starting time of x + +duration_withdraw, where x is the starting time of the (j-1)-th key. + +To change these settings, edit the following values in section +[exchange]: + +- SIGNKEY_DURATION: How long should one signing key be used? + +- LOOKAHEAD_SIGN: How much time we want to cover with our signing keys? + Note that if SIGNKEY_DURATION is bigger than LOOKAHEAD_SIGN, + ``taler-exchange-keyup`` will generate a quantity of signing keys + which is sufficient to cover all the gap. + +.. _Deployment: + +Deployment +========== + +.. _Keys-generation: + +Keys generation +--------------- + +Once the configuration is properly set up, all the keys can be generated +by the tool ``taler-exchange-keyup``. The following command generates +denomkeys and signkeys, plus the "blob" that is to be signed by the +auditor. + +:: + + taler-exchange-keyup -o blob + +*blob* contains data about denomkeys that the exchange operator needs to +get signed by every auditor he wishes (or is forced to) work with. + +In a normal scenario, an auditor must have some way of receiving the +blob to sign (Website, manual delivery, ..). Nonetheless, the exchange +admin can fake an auditor signature — for testing purposes — by running +the following command + +:: + + taler-auditor-sign -m EXCHANGE_MASTER_PUB -r BLOB -u AUDITOR_URL -o OUTPUT_FILE + +Those arguments are all mandatory. + +- ``EXCHANGE_MASTER_PUB`` the base32 Crockford-encoded exchange’s + master public key. Tipically, this value lies in the configuration + option ``[exchange]/master_public_key``. + +- ``BLOB`` the blob generated in the previous step. + +- ``AUDITOR_URL`` the URL that identifies the auditor. + +- ``OUTPUT_FILE`` where on the disk the signed blob is to be saved. + +``OUTPUT_FILE`` must then be copied into the directory specified by the +option ``AUDITOR_BASE_DIR`` under the section ``[exchangedb]``. Assuming +``AUDITOR_BASE_DIR = ${HOME}/.local/share/taler/auditors``, the +following command will "add" the auditor identified by ``AUDITOR_URL`` +to the exchange. + +:: + + cp OUTPUT_FILE ${HOME}/.local/share/taler/auditors + +If the auditor has been correctly added, the exchange’s ``/keys`` +response must contain an entry in the ``auditors`` array mentioning the +auditor’s URL. + +.. _Database-upgrades: + +Database upgrades +----------------- + +Currently, there is no way to upgrade the database between Taler +versions. + +The exchange database can be re-initialized using: + +:: + + $ taler-exchange-dbinit -r + +However, running this command will result in all data in the database +being lost, which may result in significant financial liabilities as the +exchange can then not detect double-spending. Hence this operation must +not be performed in a production system. + +.. _Diagnostics: + +Diagnostics +=========== + +This chapter includes various (very unpolished) sections on specific +topics that might be helpful to understand how the exchange operates, +which files should be backed up. The information may also be helpful for +diagnostics. + +.. _Reserve-management: + +Reserve management +------------------ + +Incoming transactions to the exchange’s provider result in the creation +or update of reserves, identified by their reserve key. The command line +tool taler-exchange-reservemod allows create and add money to reserves +in the exchange’s database. + +.. _Database-Scheme: + +Database Scheme +--------------- + +The exchange database must be initialized using taler-exchange-dbinit. +This tool creates the tables required by the Taler exchange to operate. +The tool also allows you to reset the Taler exchange database, which is +useful for test cases but should never be used in production. Finally, +taler-exchange-dbinit has a function to garbage collect a database, +allowing administrators to purge records that are no longer required. + +The database scheme used by the exchange look as follows: + +.. image:: exchange-db.png + +.. _Signing-key-storage: + +Signing key storage +------------------- + +The private online signing keys of the exchange are stored in a +subdirectory "signkeys/" of the "KEYDIR" which is an option in the +"[exchange]" section of the configuration file. The filename is the +starting time at which the signing key can be used in microseconds since +the Epoch. The file format is defined by the struct +TALER_EXCHANGEDB_PrivateSigningKeyInformationP: + +:: + + struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP { + struct TALER_ExchangePrivateKeyP signkey_priv; + struct TALER_ExchangeSigningKeyValidityPS issue; + }; + +.. _Denomination-key-storage: + +Denomination key storage +------------------------ + +The private denomination keys of the exchange are store in a +subdirectory "denomkeys/" of the "KEYDIR" which is an option in the +"[exchange]" section of the configuration file. "denomkeys/" contains +further subdirectories, one per denomination. The specific name of the +subdirectory under "denomkeys/" is ignored by the exchange. However, the +name is important for the "taler-exchange-keyup" tool that generates the +keys. The tool combines a human-readable encoding of the denomination +(i.e. for EUR:1.50 the prefix would be "EUR_1_5-", or for EUR:0.01 the +name would be "EUR_0_01-") with a postfix that is a truncated +Crockford32 encoded hash of the various attributes of the denomination +key (relative validity periods, fee structure and key size). Thus, if +any attributes of a coin change, the name of the subdirectory will also +change, even if the denomination remains the same. + +Within this subdirectory, each file represents a particular denomination +key. The filename is the starting time at which the signing key can be +used in microseconds since the Epoch. The format on disk begins with a +struct TALER_EXCHANGEDB_DenominationKeyInformationP giving the +attributes of the denomination key and the associated signature with the +exchange’s long-term offline key: + +:: + + struct TALER_EXCHANGEDB_DenominationKeyInformationP { + struct TALER_MasterSignatureP signature; + struct TALER_DenominationKeyValidityPS properties; + }; + +This is then followed by the variable-size RSA private key in +libgcrypt’s S-expression format, which can be decoded using +GNUNET_CRYPTO_rsa_private_key_decode(). + +.. _Revocations: + +Revocations +~~~~~~~~~~~ + +When an exchange goes out of business or detects that the private key of +a denomination key pair has been compromised, it may revoke some or all +of its denomination keys. At this point, the hashes of the revoked keys +must be returned as part of the ``/keys`` response under “payback”. +Wallets detect this, and then return unspent coins of the respective +denomination key using the ``/payback`` API. + +When a denomination key is revoked, a revocation file is placed into the +respective subdirectory of “denomkeys/”. The file has the same prefix as +the file that stores the struct +TALER_EXCHANGEDB_DenominationKeyInformationP information, but is +followed by the “.rev” suffix. It contains a 64-byte EdDSA signature +made with the master key of the exchange with purpose +``TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED``. If such a file is +present, the exchange must check the signature and if it is valid treat +the respective denomination key as revoked. + +Revocation files can be generated using the ``taler-exchange-keyup`` +command-line tool using the ``-r`` option. The Taler auditor will +instruct operators to generate revocations if it detects a key +compromise (which is possible more coins of a particular denomination +were deposited than issued). + +It should be noted that denomination key revocations should only happen +under highly unusual (“emergency”) conditions and not under normal +conditions. + +.. _Auditor-signature-storage: + +Auditor signature storage +------------------------- + +Signatures from auditors are stored in the directory specified in the +exchange configuration section "exchangedb" under the option +"AUDITOR_BASE_DIR". The exchange does not care about the specific names +of the files in this directory. + +Each file must contain a header with the public key information of the +auditor, the master public key of the exchange, and the number of signed +denomination keys: + +:: + + struct AuditorFileHeaderP { + struct TALER_AuditorPublicKeyP apub; + struct TALER_MasterPublicKeyP mpub; + uint32_t dki_len; + }; + +This is then followed by dki_len signatures of the auditor of type +struct TALER_AuditorSignatureP, which are then followed by another +dki_len blocks of type struct TALER_DenominationKeyValidityPS. The +auditor’s signatures must be signatures over the information of the +corresponding denomination key validity structures embedded in a struct +TALER_ExchangeKeyValidityPS structure using the +TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS purpose. + + +.. [1] + Naturally, you could operate a Taler exchange for a toy currency + without any real value on low-cost setups like a Raspberry Pi, but we + urge you to limit the use of such setups to research and education as + with GNU Taler data loss instantly results in financial losses. + +.. [2] + The current implementation does not make provisions for secret + splitting. Still, the use of a hardware security module (HSM) for + protecting private keys is adviseable, so please contact the + developers for HSM integration support. + +.. [3] + https://api.taler.net/api-exchange.html#wire-req + diff --git a/taler-uri.rst b/taler-uri.rst deleted file mode 100644 index d69b4b0c..00000000 --- a/taler-uri.rst +++ /dev/null @@ -1,84 +0,0 @@ -==================== -The taler URI scheme -==================== - -The `taler` URI scheme represents actions that are processed by a Taler wallet. The basic syntax is as follows: - -.. code:: none - - 'taler://' action '/' params - --------------------- -Requesting a Payment --------------------- - -Payments are requested with the `pay` action. The parameters are a hierarchical identifier for the requested payment: - - -.. code:: none - - 'taler://pay/' merchant-host '/' merchant-query '/' merchant-instance '/' order-id [ '/' session-id ] - -The components `merchant-host`, `merchant-query` and `order-id` identify the URL that is used to claim the contract -for this payment request. - -To make the URI shorter (which is important for QR code payments), `-` (minus) can be substituted to get a default value -for some components: - -* the default for `merchant-instance` is `default` -* the default for `merchant-query` is `/public/proposal` - -The following is a minimal example for a payment request from the demo merchant, using the default instance and no session-bound payment: - -.. code:: none - - taler://pay/backend.demo.taler.net/-/-/2019.08.26-ABCED - - ------------ -Withdrawing ------------ - -.. code:: none - - 'taler://withdraw/' bank-host '/' bank-query '/' withdraw-uid - -When `bank-query` is `-`, the default `withdraw-operation` will be used. - -Example: - -.. code:: none - - 'taler://withdraw/bank.taler.net/-/ABDE123 - - -------------------------- -Low-level Reserve Actions -------------------------- - -The following actions are deprecated. They might not be supported -in newer wallets. - -.. code:: none - - 'taler://reserve-create/' reserve-pub - -.. code:: none - - 'taler://reserve-confirm/' query - ----------------------------- -Special URLs for fulfillment ----------------------------- - -The special `fulfillment-success` action can be used in a fulfillment URI to indicate success -with a message, without directing the user to a website. This is useful in applications that are not Web-based: - -When wallets encounter this URI in any other circumstance than going to a fulfillment URL, they must raise an error. - -Example: - -.. code:: none - - taler://fulfillment-success/Thank+you+for+donating+to+GNUnet - diff --git a/wireformats.rst b/wireformats.rst deleted file mode 100644 index 12d23630..00000000 --- a/wireformats.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. _wireformats: - -Wire Transfer Methods -===================== - -A wire transfer is essential for the exchange to transfer funds into a merchant's -account upon a successful deposit (see :ref:`deposit request `). The -merchant has to include the necessary information for the exchange to initiate the -wire transfer. - -The information required for wire transfer depends on the method of wire transfer -used. Since the wire transfers differ for each region, we document here the -ones currently supported by the exchange. - -X-TALER-BANK ------------- - -The "x-taler-bank" wire format is used for testing and for integration with Taler's -simple "bank" system which in the future might be useful to setup a bank -for a local / regional currency or accounting system. Using the @code{x-taler-bank} -wire method in combination with the Taler's bank, it is thus possible to -fully test the Taler system without using "real" currencies. The URL -format for "x-taler-bank" is simple, in that it only specifies an account -number and the URL of the bank: - - * payto://x-taler-bank/BANK_URI/ACCOUNT_NUMBER - -The account number given must be a positive 53-bit integer. As with -any payto://-URI, additional fields may be present (after a ?), but -are not required. The BANK_URI may include a port number. If none is -given, @code{https} over port 443 is assumed. If a port number is -given, @code{http} over the given port is to be used. Note that this -means that you cannot run an x-taler-bank over @code{https} on a -non-canonical port. - -Note that a particular exchange is usually only supporting one -particular bank with the "x-taler-bank" wire format, so it is not -possible for a merchant with an account at a different bank to use -"x-taler-bank" to transfer funds across banks. After all, this is for -testing and not for real banking. - -The "x-taler-bank" method is implemented by the @code{taler_bank} plugin. - - -SEPA ----- - -The Single Euro Payments Area (SEPA) [#sepa]_ is a regulation for electronic -payments. Since its adoption in 2012, all of the banks in the Eurozone and some -banks in other countries adhere to this standard for sending and receiving -payments. Note that the currency of the transfer will (currently) always be *EUR*. In -case the receiving account is in a currency other than EURO, the receiving bank -may covert the amount into that currency; currency exchange charges may be -levied by the receiving bank. - -For the merchant to receive deposits through SEPA, the deposit request must -follow the payto:// specification for SEPA: - - * payto://sepa/IBAN - - -The implementation of the @code{ebics} plugin which is envisioned to -support the @code{sepa} method is currently incomplete. Specifically, -we need a working implementation of `libebics` which is a sub-project -trying to implement the EBICS [#ebics]_ standard. - -.. [#sepa] SEPA - Single Euro Payments Area: - http://www.ecb.europa.eu/paym/sepa/html/index.en.html -.. [#ebics] EBCIS - European Banking Computer Interface Standard - http://www.ebics.org/ -- cgit v1.2.3