From 735fb8a89f51875196783b167e8ae622368808fc Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Mon, 26 Dec 2016 18:42:18 +0100 Subject: Still on splitting --- Makefile | 90 +- api-bank.rst | 81 -- api-common.rst | 705 ------------- api-error.rst | 1204 ---------------------- api-exchange.rst | 1527 ---------------------------- api-merchant.rst | 699 ------------- api/api-bank.rst | 81 ++ api/api-common.rst | 705 +++++++++++++ api/api-error.rst | 1204 ++++++++++++++++++++++ api/api-exchange.rst | 1527 ++++++++++++++++++++++++++++ api/api-merchant.rst | 699 +++++++++++++ api/conf.py | 285 ++++++ api/exts/__pycache__/tsref.cpython-35.pyc | Bin 0 -> 7457 bytes api/exts/tsref.py | 233 +++++ api/global_licensing.rst | 215 ++++ api/index.rst | 89 ++ api/integration-bank.rst | 81 ++ api/integration-general.rst | 82 ++ api/integration-merchant.rst | 315 ++++++ api/wireformats.rst | 69 ++ conf.py | 285 ------ configuration-basics.rst | 79 -- deployment.rst | 231 ----- dev-exchange.rst | 144 --- dev-merchant.rst | 38 - dev-wallet-wx.rst | 212 ---- docs/conf.py | 285 ++++++ docs/configuration-basics.rst | 79 ++ docs/deployment.rst | 231 +++++ docs/dev-exchange.rst | 144 +++ docs/dev-merchant.rst | 38 + docs/dev-wallet-wx.rst | 212 ++++ docs/example-essay-store.rst | 615 +++++++++++ docs/exts/__pycache__/tsref.cpython-35.pyc | Bin 0 -> 7448 bytes docs/exts/tsref.py | 233 +++++ docs/global_licensing.rst | 215 ++++ docs/glossary.rst | 106 ++ docs/index.rst | 104 ++ docs/operate-exchange.rst | 246 +++++ docs/operate-merchant.rst | 212 ++++ example-essay-store.rst | 615 ----------- exts/tsref.py | 233 ----- global_licensing.rst | 215 ---- glossary.rst | 106 -- index.rst | 124 --- integration-bank.rst | 81 -- integration-general.rst | 82 -- integration-merchant.rst | 315 ------ operate-exchange.rst | 246 ----- operate-merchant.rst | 212 ---- wireformats.rst | 69 -- 51 files changed, 8350 insertions(+), 7548 deletions(-) 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 create mode 100644 api/api-bank.rst create mode 100644 api/api-common.rst create mode 100644 api/api-error.rst create mode 100644 api/api-exchange.rst create mode 100644 api/api-merchant.rst create mode 100644 api/conf.py create mode 100644 api/exts/__pycache__/tsref.cpython-35.pyc create mode 100644 api/exts/tsref.py create mode 100644 api/global_licensing.rst create mode 100644 api/index.rst create mode 100644 api/integration-bank.rst create mode 100644 api/integration-general.rst create mode 100644 api/integration-merchant.rst create mode 100644 api/wireformats.rst delete mode 100644 conf.py delete mode 100644 configuration-basics.rst delete mode 100644 deployment.rst delete mode 100644 dev-exchange.rst delete mode 100644 dev-merchant.rst delete mode 100644 dev-wallet-wx.rst create mode 100644 docs/conf.py create mode 100644 docs/configuration-basics.rst create mode 100644 docs/deployment.rst create mode 100644 docs/dev-exchange.rst create mode 100644 docs/dev-merchant.rst create mode 100644 docs/dev-wallet-wx.rst create mode 100644 docs/example-essay-store.rst create mode 100644 docs/exts/__pycache__/tsref.cpython-35.pyc create mode 100644 docs/exts/tsref.py create mode 100644 docs/global_licensing.rst create mode 100644 docs/glossary.rst create mode 100644 docs/index.rst create mode 100644 docs/operate-exchange.rst create mode 100644 docs/operate-merchant.rst delete mode 100644 example-essay-store.rst delete mode 100644 exts/tsref.py delete mode 100644 global_licensing.rst delete mode 100644 glossary.rst delete mode 100644 index.rst delete mode 100644 integration-bank.rst delete mode 100644 integration-general.rst delete mode 100644 integration-merchant.rst delete mode 100644 operate-exchange.rst delete mode 100644 operate-merchant.rst delete mode 100644 wireformats.rst diff --git a/Makefile b/Makefile index b6461376..9155d682 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +ALLSPHINXOPTS = -d $(PWD)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . @@ -54,41 +54,41 @@ clean: # The html-linked builder does not support caching, so we # remove all cached state first. html: - $(SPHINXBUILD) -b html-linked $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/html - $(SPHINXBUILD) -b html-linked $(ALLSPHINXOPTS) $(APIBUILDDIR)/html + $(SPHINXBUILD) docs/ -b html-linked $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b html-linked $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo @echo "Build finished. The HTML pages are in $(APIBUILDDIR)/html." @echo "Build finished. The HTML pages are in $(DOCSBUILDDIR)/html." dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/dirhtml - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(APIBUILDDIR)/dirhtml + $(SPHINXBUILD) docs/ -b dirhtml $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b dirhtml $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo @echo "Build finished. The HTML pages are in $(APIBUILDDIR)/dirhtml." @echo "Build finished. The HTML pages are in $(DOCSBUILDDIR)/dirhtml." singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/singlehtml - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(APIBUILDDIR)/singlehtml + $(SPHINXBUILD) docs/ -b singlehtml $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b singlehtml $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo @echo "Build finished. The HTML page is in $(DOCSBUILDDIR)/singlehtml." @echo "Build finished. The HTML page is in $(APIBUILDDIR)/singlehtml." pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(APIBUILDDIR)/pickle - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/pickle + $(SPHINXBUILD) api/ -b pickle $(ALLSPHINXOPTS) $(APIBUILDDIR) + $(SPHINXBUILD) docs/ -b pickle $(ALLSPHINXOPTS) $(DOCSBUILDDIR) @echo @echo "Build finished; now you can process the pickle files." json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/json - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(APIBUILDDIR)/json + $(SPHINXBUILD) docs/ -b json $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b json $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo @echo "Build finished; now you can process the JSON files." htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/htmlhelp - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(APIBUILDDIR)/htmlhelp + $(SPHINXBUILD) docs/ -b htmlhelp $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b htmlhelp $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(DOCSBUILDDIR)/htmlhelp." @@ -96,8 +96,8 @@ htmlhelp: ".hhp project file in $(APIBUILDDIR)/htmlhelp." qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/qthelp - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(APIBUILDDIR)/qthelp + $(SPHINXBUILD) docs/ -b qthelp $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b qthelp $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(DOCSBUILDDIR)/qthelp, like this:" @@ -112,8 +112,8 @@ qthelp: devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(APIBUILDDIR)/devhelp - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/devhelp + $(SPHINXBUILD) api/ -b devhelp $(ALLSPHINXOPTS) $(APIBUILDDIR) + $(SPHINXBUILD) docs/ -b devhelp $(ALLSPHINXOPTS) $(DOCSBUILDDIR) @echo @echo "Build finished." @echo "To view the help file:" @@ -123,15 +123,15 @@ devhelp: @echo "# devhelp" epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(APIBUILDDIR)/epub - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/epub + $(SPHINXBUILD) api/ -b epub $(ALLSPHINXOPTS) $(APIBUILDDIR) + $(SPHINXBUILD) docs/ -b epub $(ALLSPHINXOPTS) $(DOCSBUILDDIR) @echo @echo "Build finished. The epub file is in $(APIBUILDDIR)/epub." @echo "Build finished. The epub file is in $(DOCSBUILDDIR)/epub." latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(APIBUILDDIR)/latex - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/latex + $(SPHINXBUILD) api/ -b latex $(ALLSPHINXOPTS) $(APIBUILDDIR) + $(SPHINXBUILD) docs/ -b latex $(ALLSPHINXOPTS) $(DOCSBUILDDIR) @echo @echo "Build finished; the LaTeX files are in $(APIBUILDDIR)/latex." @echo "Build finished; the LaTeX files are in $(DOCSBUILDDIR)/latex." @@ -139,8 +139,8 @@ latex: "(use \`make latexpdf' here to do that automatically)." latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(APIBUILDDIR)/latex - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/latex + $(SPHINXBUILD) api/ -b latex $(ALLSPHINXOPTS) $(APIBUILDDIR) + $(SPHINXBUILD) docs/ -b latex $(ALLSPHINXOPTS) $(DOCSBUILDDIR) @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(DOCSBUILDDIR)/latex all-pdf $(MAKE) -C $(APIBUILDDIR)/latex all-pdf @@ -148,8 +148,8 @@ latexpdf: @echo "pdflatex finished; the PDF files are in $(DOCSBUILDDIR)/latex." latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/latex - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(APIBUILDDIR)/latex + $(SPHINXBUILD) docs/ -b latex $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b latex $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(APIBUILDDIR)/latex all-pdf-ja $(MAKE) -C $(DOCSBUILDDIR)/latex all-pdf-ja @@ -157,22 +157,22 @@ latexpdfja: @echo "pdflatex finished; the PDF files are in $(APIBUILDDIR)/latex." text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/text - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(APIBUILDDIR)/text + $(SPHINXBUILD) docs/ -b text $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b text $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo @echo "Build finished. The text files are in $(DOCSBUILDDIR)/text." @echo "Build finished. The text files are in $(APIBUILDDIR)/text." man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/man - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(APIBUILDDIR)/man + $(SPHINXBUILD) docs/ -b man $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b man $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo @echo "Build finished. The manual pages are in $(DOCSBUILDDIR)/man." @echo "Build finished. The manual pages are in $(APIBUILDDIR)/man." texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/texinfo - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(APIBUILDDIR)/texinfo + $(SPHINXBUILD) docs/ -b texinfo $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b texinfo $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo @echo "Build finished. The Texinfo files are in $(DOCSBUILDDIR)/texinfo." @echo "Build finished. The Texinfo files are in $(APIBUILDDIR)/texinfo." @@ -180,8 +180,8 @@ texinfo: "(use \`make info' here to do that automatically)." info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/texinfo - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(APIBUILDDIR)/texinfo + $(SPHINXBUILD) docs/ -b texinfo $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b texinfo $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo "Running Texinfo files through makeinfo..." make -C $(DOCSBUILDDIR)/texinfo info make -C $(APIBUILDDIR)/texinfo info @@ -189,22 +189,22 @@ info: @echo "makeinfo finished; the Info files are in $(APIBUILDDIR)/texinfo." gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(DOCSBUILDDIR)/locale - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(APIBUILDDIR)/locale + $(SPHINXBUILD) docs/ -b gettext $(I18NSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b gettext $(I18NSPHINXOPTS) $(APIBUILDDIR) @echo @echo "Build finished. The message catalogs are in $(DOCSBUILDDIR)/locale." @echo "Build finished. The message catalogs are in $(APIBUILDDIR)/locale." changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/changes - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(APIBUILDDIR)/changes + $(SPHINXBUILD) docs/ -b changes $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b changes $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo @echo "The overview file is in $(DOCSBUILDDIR)/changes." @echo "The overview file is in $(APIBUILDDIR)/changes." linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/linkcheck - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(APIBUILDDIR)/linkcheck + $(SPHINXBUILD) docs/ -b linkcheck $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b linkcheck $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(APIBUILDDIR)/linkcheck/output.txt." @@ -213,8 +213,8 @@ linkcheck: doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/doctest - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(APIBUILDDIR)/doctest + $(SPHINXBUILD) docs/ -b doctest $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b doctest $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo "Testing of doctests in the sources finished, look at the " \ "results in $(APIBUILDDIR)/doctest/output.txt." @echo "Testing of doctests in the sources finished, look at the " \ @@ -222,15 +222,15 @@ doctest: xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/xml - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(APIBUILDDIR)/xml + $(SPHINXBUILD) docs/ -b xml $(ALLSPHINXOPTS) $(DOCSBUILDDIR) + $(SPHINXBUILD) api/ -b xml $(ALLSPHINXOPTS) $(APIBUILDDIR) @echo @echo "Build finished. The XML files are in $(DOCSBUILDDIR)/xml." @echo "Build finished. The XML files are in $(APIBUILDDIR)/xml." pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(APIBUILDDIR)/pseudoxml - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(DOCSBUILDDIR)/pseudoxml + $(SPHINXBUILD) api/ -b pseudoxml $(ALLSPHINXOPTS) $(APIBUILDDIR) + $(SPHINXBUILD) docs/ -b pseudoxml $(ALLSPHINXOPTS) $(DOCSBUILDDIR) @echo @echo "Build finished. The pseudo-XML files are in $(DOCSBUILDDIR)/pseudoxml." @echo "Build finished. The pseudo-XML files are in $(APIBUILDDIR)/pseudoxml." diff --git a/api-bank.rst b/api-bank.rst deleted file mode 100644 index 48b7075e..00000000 --- a/api-bank.rst +++ /dev/null @@ -1,81 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014, 2015, 2016 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 - -========= -Bank API -========= - -The following APIs are served from banks, in order to allow exchanges to -deposit funds to money recipients. A typical scenario for calling this -APIs is after a merchant has deposited coins to the exchange, and the exchange -needs to give real money to the merchant. - ------------------- -Administrative API ------------------- - -This is `local` API, meant to make the bank communicate with trusted entities, -namely exchanges. - -.. _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 - -:status 400 Bad Request: The bank replies a `BankIncomingError`_ object - -**Details:** - -.. _BankDepositRequest: -.. code-block:: tsref - - interface BankDepositRequest { - - // JSON 'amount' object. The amount the caller wants to transfer - // to the recipient's count - amount: Amount; - - // The id of this wire transfer - wtid: base32; - - // The sender's account identificator - debit_account: number; - - // The recipient's account identificator - credit_account: number; - - } - -.. _BankIncomingError: -.. code-block:: tsref - - interface BankIncomingError { - - // Human readable explanation of the failure. - reason: string - - } - --------- -Util API --------- - -Whenever the user wants to know the bank account number of a public account, -the following path returns a human readable HTML containing this information - - `/public-accounts/details?account=accountName` diff --git a/api-common.rst b/api-common.rst deleted file mode 100644 index 411f7df5..00000000 --- a/api-common.rst +++ /dev/null @@ -1,705 +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 -^^^^^^^ - -Amounts of currency are expressed as a JSON object with the following fields: - -.. _`tsref-type-Amount`: - -.. code-block:: tsref - - interface Amount { - // 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 { - /** - * 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 :ref:`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; - struct GNUNET_HashCode h_wire; - struct GNUNET_TIME_AbsoluteNBO timestamp; - struct GNUNET_TIME_AbsoluteNBO refund_deadline; - uint64_t transaction_id; - 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; - struct GNUNET_HashCode h_wire; - uint64_t transaction_id GNUNET_PACKED; - 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; - }; - - 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_SEPA_DETAILS || TALER_SIGNATURE_MASTER_TEST_DETAILS - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct GNUNET_HashCode h_sepa_details; - }; - - 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; - struct GNUNET_HashCode h_wire; - uint64_t transaction_id; - struct TALER_MerchantPublicKeyP merchant; - struct TALER_CoinSpendPublicKeyP coin_pub; - }; - - /** - * Format internally used for packing the detailed information - * to generate the signature for /track/transfer signatures. - */ - struct TALER_WireDepositDetailP { - struct GNUNET_HashCode h_contract; - struct GNUNET_TIME_AbsoluteNBO execution_time; - uint64_t transaction_id GNUNET_PACKED; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_AmountNBO deposit_value; - struct TALER_AmountNBO deposit_fee; - }; - - - struct TALER_WireDepositDataPS { - /** - * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - struct TALER_AmountNBO total; - 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; - }; - - -.. _TALER_ContractPS: -.. sourcecode:: c - - struct TALER_ContractPS { - /** - * purpose.purpose = TALER_SIGNATURE_MERCHANT_CONTRACT - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - uint64_t transaction_id; - struct TALER_AmountNBO total_amount; - struct TALER_AmountNBO max_fee; - struct GNUNET_HashCode h_contract; - struct TALER_MerchantPublicKeyP merchant_pub; - }; - - 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; - struct TALER_WireTransferIdentifierRawP wtid; - struct TALER_CoinSpendPublicKeyP coin_pub; - uint64_t transaction_id; - 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 GNUNET_PACKED; - uint64_t transaction_id GNUNET_PACKED; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_MerchantPublicKeyP merchant; - uint64_t rtransaction_id GNUNET_PACKED; - struct TALER_AmountNBO refund_amount; - struct TALER_AmountNBO refund_fee; - }; diff --git a/api-error.rst b/api-error.rst deleted file mode 100644 index cf107b11..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 7f1a1516..00000000 --- a/api-exchange.rst +++ /dev/null @@ -1,1527 +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 - -============================= -The Exchange RESTful JSON API -============================= - -The API specified here follows the :ref:`general conventions ` -for all details not specified in the individual requests. The :ref:`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. - - **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 { - // EdDSA master public key of the exchange, used to sign entries in `denoms` and `signkeys` - master_public_key: EddsaPublicKey; - - // Denomination offered by this exchange. - denoms: Denom[]; - - // 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. - - 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 { - // The key is a supported method (i.e. "sepa" or "test"). - // The value is a method-specific JSON object with account details - // (i.e. IBAN number, owner name, bank address, etc.). - // The value objects may also contain signatures (if applicable). - // - // A single /wire response can contain an arbitrary number of these - // string-object pairs. However, the keys must be unique. - string: Object; - } - - Possible encodings for the objects are right now the following: - - .. _WireTestResponse: - .. _tsref-type-WireTestResponse: - .. code-block:: tsref - - interface WireTestResponse { - // Mandatory indicator that this is a TEST wire response. - type: "test"; - - // Account number at the bank - account_number: number; - - // URI of the bank - bank_uri: string; - - // Name of the account's owner - name: string; - - // Salt used to sign, `base32`_ encoded - salt: string; - - // Signaure of `TALER_MasterWireDetailsPS`_ with purpose TALER_SIGNATURE_MASTER_TEST_DETAILS - // Note that the `h_sepa_details` field of `TALER_MasterWireDetailsPS`_ is computed - // by concatenating all of the above fields (in the same order they appear) and then - // by hashing the obtained concatenation. - sig: EddsaSignature; - } - - .. _WireSepaResponse: - .. _tsref-type-WireSepaResponse: - .. code-block:: tsref - - interface WireSepaResponse { - // Mandatory indicator that this is a SEPA wire response. - type: "sepa"; - - // Legal name of the owner of the account - receiver_name: string; - - // IBAN account number. - iban: string; - - // BIC of the bank. - bic: string; - - // Signaure of `TALER_MasterWireDetailsPS`_ with purpose TALER_SIGNATURE_MASTER_SEPA_DETAILS - // Note that the `h_sepa_details` field of `TALER_MasterWireDetailsPS`_ is computed - // by concatenating all of the above fields (in the same order they appear) and then - // by hashing the obtained concatenation. - 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" or "DEPOSIT" - type: string; - - // The amount that was withdrawn or deposited. - amount: Amount; - - // Sender account details, only present if type is "DEPOSIT". - sender_account_details?: any; - - // Transfer details uniquely identifying the transfer, only present if type is "DEPOSIT". - transfer_details?: any; - - // `base32`_ encoding of `TALER_WithdrawRequestPS`_ with purpose TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW. This field appears only if `type` is "WITHDRAW". - details?: string; - - // Signature of `TALER_WithdrawRequestPS`_ created with the `reserves's private key `_. Only present if type is "WITHDRAW". - signature?: EddsaSignature; - } - - -.. 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 { - // Denomination public key (RSA), specifying the type of coin the client - // would like the exchange to create. - denom_pub: RsaPublicKey; - - // 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: - 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. - 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: HashCode; - - // `coin's public key `_, both ECDHE and EdDSA. - coin_pub: CoinPublicKey; - - // denomination RSA key with which the coin is signed - denom_pub: RsaPublicKey; - - // 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 - timestamp: Timestamp; - - // indicative time by which the exchange undertakes to transfer the funds to - // the merchant, in case of successful payment. - pay_deadline: Timestamp; - - // 64-bit transaction id for the transaction between merchant and customer - transaction_id: number; - - // 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" or "melt" or "refund" - 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; - - // `base32`_ binary encoding of the transaction data as a - // `TALER_DepositRequestPS`_ or `TALER_RefreshMeltCoinAffirmationPS`_ - // or `TALER_RefundRequestPS`_ - details: string; - - // `EdDSA Signature `_ of what we got in `details`. - // Note that in the case of a 'refund', the signature is made with - // the `public key of the merchant `_, and not `that of the coin `_ - signature: EddsaSignature; - } - ----------- -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 { - // Array of `n` new denominations to order. - new_denoms: RsaPublicKey[]; - - // Information about coin being melted. - melt_coin: MeltCoin; - - // The outer dimension of the 2d array has `kappa` entries - // for the cut-and-choose protocol. - // The inner array contains `n` entries with blinded coins, - // matching the respective entries in `new_denoms`. - coin_evs: CoinEnvelope[][]; - - // `kappa` transfer public keys (ephemeral ECDHE keys) - transfer_pubs: EddsaPublicKey[]; - - } - - 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`. The `melt_coin` field is a list of JSON - objects with the following fields: - - - .. _tsref-type-MeltCoin: - .. code-block:: tsref - - interface MeltCoin { - // `Coin public key `_, uniquely identifies the coin - coin_pub: string; - - // The denomination public key allows the exchange to determine total coin value. - denom_pub: RsaPublicKey; - - // Signature over the `coin public key `_ by the denomination. - denom_sig: RsaSignature; - - // Signature by the `coin `_ over the session public key. - 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; - } - - 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. - - - .. _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. - Request body contains a JSON object with the following fields: - - - :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`_. - - - - .. code-block:: tsref - - interface RevealRequest { - // Hash over most of the arguments to the /exchange/melt step. Used to - // identify the corresponding melt operation. For details on which elements - // must be hashed in which order, please consult the source code of the exchange - // reference implementation. - session_hash: HashCode; - - // Array of `kappa - 1` ECDHE transfer private keys. - // The exchange will use those to decrypt the transfer secrets, - // and then decrypt the private keys and blinding factors - // of the coins to be generated and check all this against the commitments. - transfer_privs: EddsaPrivateKey[]; - } - - - .. _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; - - // Signature of the coin over the melting operation. - coin_sig: EddsaSignature; - - // Coin that we failed to successfully melt. - coin_pub: EddsaPublicKey; - - // Amount of the value of the coin to be melted in the refresh session. - melt_amount_with_fee: Amount; - - // Fee that was due for the melting for the coin. - melt_fee: Amount; - - // Denomination keys to be used for the coins to be withdrawn. - newcoin_infos: RsaPublicKey[]; - - // Array of blinded coins to be withdrawn. Same length as - // `newcoin_infos`. - commit_infos: CoinEnvelope[]; - - // Transfer public key at index `gamma`. - gamma_tp: EddsaPublicKey; - - // Specific `gamma` value chosen by the exchange. - gamma: number; - - } - - - .. _tsref-type-LinkInfo: - .. code-block:: tsref - - interface LinkInfo { - // the transfer ECDHE public key - transfer_pub: EddsaPublicKey; - - } - - .. _tsref-type-CommitInfo: - .. code-block:: tsref - - interface CommitInfo { - coin_ev: BlindedRsaSignature; - - } - - -.. 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 - // decrypt the `secret_enc` in combination with the private key of - // `coin_pub`. - transfer_pub: EcdhePublicKey; - - // ECDHE-encrypted link secret that, once decrypted, can be used to - // decrypt/unblind the `new_coins`. - secret_enc: Base32; - - // 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; - } - - - - ------------------------ -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; - - // 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: HashCode; - - // 64-bit transaction id for the transaction between merchant and - // customer - transaction_id: number; - - // 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: HashCode; - - // coin's public key, both ECDHE and EdDSA. - coin_pub: CoinPublicKey; - - // 64-bit transaction id for the transaction between merchant and customer - transaction_id: number; - - // 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 -------- - - .. note:: - - Refunds are currently not implemented (#3641), this documentation is thus a bit preliminary and may still change. - -.. _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: HashCode; - - // coin's public key, both ECDHE and EdDSA. - coin_pub: CoinPublicKey; - - // 64-bit transaction id of the original transaction between merchant and customer - transaction_id: number; - - // 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; - } - ------------------------------- -Administrative API: Key update ------------------------------- - - .. note:: - - This is not yet implemented (no bug number yet, as we are not sure we will - implement this; for now, adding new files to the directory and sending a - signal to the exchange process seems to work fine). - -New denomination and signing keys can be uploaded to the exchange via the -HTTP interface. It is, of course, only possible to upload keys signed -by the exchange's master key. Furthermore, this API should probably only -be used via loopback, as we want to protect the private keys from -interception. - -.. http:POST:: /admin/add/denomination_key - - Upload a new denomination key. - - **Request:** - - .. code-block:: tsref - - { - // Public part of the denomination key - denom_info: any: - - // Private RSA key - denom_priv: RsaPrivateKey; - } - - -.. http:POST:: /admin/add/sign_key - - Upload a new signing key. - - **Request:** - - .. code-block:: tsref - - { - // Public part of the signing key - sign_info: any; - - // Private EdDSA key - sign_priv: EddsaPrivateKey; - } - -.. _add-incoming: - -------------------------------------- -Administrative API: Bank transactions -------------------------------------- - -.. http:POST:: /admin/add/incoming - - Notify exchange of an incoming transaction to fill a reserve. - - **Request:** - - .. code-block:: tsref - - { - // Reserve public key - reserve_pub: EddsaPublicKey; - - // Amount transferred to the reserve - amount: Amount; - - // When was the transaction executed - execution_date: Timestamp; - - // Sender's wire account details, so that the exchange knows from whom the - // money comes from (and can possibly refund it). The details - // given here must be in a wire format supported by the exchange. - sender_account_details: any; - - // The wire details given here should include an unique identifier - // for each transaction. The exchange will check that the details - // given are unique, and if the wire details are identical to previous - // wire details will treat the request as a duplicate and not actually - // do any update. This is true even if the amount or execution date - // differs. - // - // Note that the exchange does not interpret these details in any - // way, other than for "being unique". They are stored for diagnostics - // and auditing. - transfer_details: any; - } - - **Response:** - - :status 200: - The operation succeeded. The body is an `AddIncomingResponse`_ object. - :status 403: - the client is not permitted to add incoming transactions. The request may - be disallowed by the configuration in general or restricted to certain IP - addresses (i.e. loopback-only). - - - .. _AddIncomingResponse: - .. code-block:: tsref - - interface AddIncomingResponse { - // The string constant `NEW` or `DUP` to indicate whether the transaction - // was truly added to the DB or whether it already existed in the DB - status: string; - } - -.. http:POST:: /admin/add/outgoing - - Notify exchange about the completion of an outgoing transaction satisfying a - /deposit request. In the future, this will allow merchants to obtain details - about the /deposit requests they send to the exchange. - - .. note:: - - This is not yet implemented (no bug number yet either). - - **Request:** - - .. code-block:: tsref - - { - coin_pub: CoinPublicKey; - - // Amount transferred to the merchant - amount: Amount; - - // Transaction identifier in the wire details - transaction: number; - - // `Wire transaction details `_, as originally specified by the merchant - wire: Object; - } - - **Response** - - :status 200: The request was successful. - :status 403: the client is not permitted to add outgoing transactions - - If the request was successful, the response has the following format: - - .. code-block:: tsref - - { - // The string constant `NEW` or `DUP` to indicate whether the transaction - // was truly added to the DB or whether it already existed in the DB - status: string; - } - ------------- -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 9eccc2fa..00000000 --- a/api-merchant.rst +++ /dev/null @@ -1,699 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014, 2015, 2016 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 - @author Florian Dold - @author Christian Grothoff - -.. _merchant-api: - -============ -Merchant API -============ - -Before reading the API reference documentation, see the :ref:`merchant architecture` and :ref:`payprot` - ---------------------- -The Frontend HTTP API ---------------------- - -This frontend API is non-normative, and only gives an example of what a typical frontend API would look like. - -.. http:get:: contract_url - - Requesting this URL generates a contract, typically with a new (and unique) transaction id. - - **Request:** - - The request depends entirely on the merchant implementation. - - **Response** - - :status 200 OK: The request was successful. The body contains an :ref:`Offer `. - :status 400 Bad Request: Request not understood. - :status 500 Internal Server Error: - In most cases, some error occurred while the backend was generating the - contract. For example, it failed to store it into its database. - -.. _pay: -.. http:post:: pay_url - - - Send the deposit permission to the merchant. The client should POST a `DepositPermission`_ - object. If the payment was processed successfully by the merchant, this URL will set session - state that allows the fulfillment URL to show the final product. - - .. _DepositPermission: - .. code-block:: tsref - - interface DepositPermission { - // the hashed `wire details `_ of this merchant. - // The wallet takes this value as-is from the contract - H_wire: HashCode; - - // `base32`_ encoded `TALER_ContractPS`_. The wallet can choose whether - // to take this value obtained from the field `h_contract`, - // or regenerating one starting from the values it gets within the contract - H_contract: HashCode; - - // a 53-bit number corresponding to the contract being agreed on - transaction_id: number; - - // total amount being paid as per the contract (the sum of the amounts from the `coins` may be larger to cover deposit fees not covered by the merchant) - total_amount: Amount; - - // maximum fees merchant agreed to cover as per the contract - max_fee: Amount; - - // The `merchant instance `_ which is going to receive the final wire transfer. - instance: string; - - // Signature of `TALER_ContractPS`_ - merchant_sig: EddsaSignature; - - // a timestamp of this deposit permission. It equals just the contract's timestamp - timestamp: Timestamp; - - // Deadline for the customer to be refunded for this purchase - refund_deadline: Timestamp; - - // Deadline for the customer to pay for this purchase. Note that is up to the frontend - // to make sure that this value matches the one the backend signed over when the contract - // was generated. The frontend should never verify if the payment is still on time, - // because when payments are replayed it is expxectable that this deadline is expired, - // and only the backend can detect if a payment is a reply or not. - pay_deadline: Timestamp; - - // the chosen exchange's base URL - exchange: string; - - // the coins used to sign the contract - coins: DepositedCoin[]; - - } - - .. _`tsref-type-DepositedCoin`: - - .. code-block:: tsref - - interface DepositedCoin { - // the amount this coin is paying for - amount: Amount; - - // coin's public key - coin_pub: RsaPublicKey; - - // denomination key - denom_pub: RsaPublicKey; - - // exchange's signature over this `coin's public key `_ - ub_sig: RsaSignature; - - // Signature of `TALER_DepositRequestPS`_ - coin_sig: EddsaSignature; - } - - **Success Response:** - - :status 301 Redirection: the merchant should redirect the client to his fullfillment page, where the good outcome of the purchase must be shown to the user. - - **Failure Responses:** - - The error codes and data sent to the wallet are a mere copy of those gotten from the exchange when attempting to pay. The section about :ref:`deposit ` explains them in detail. - - -.. http:post:: fulfillment_url - - Returns a cooperative merchant page (called the execution page) that will - send the ``taler-execute-payment`` to the wallet and react to failure or - success of the actual payment. ``fulfillment_url`` is included in the `contract`_. - Furthermore, :ref:`payprot` documents the payment protocol between wallets and - merchants. - - The wallet will inject an ``XMLHttpRequest`` request to the merchant's - ``$pay_url`` in the context of the execution page. This mechanism is - necessary since the request to ``$pay_url`` must be made from the merchant's - origin domain in order to preserve information (e.g. cookies, origin header). - -.. http:get:: /history - - Return a list of fulfilled contracts. Typically used by backoffice interfaces. - - **Request** - - :query days: a number indicating that we request contracts from now up to `days` days ago. - - **Response** - - :status 200 OK: The response is a JSON array of `TransactionHistory`_. - -.. http:get:: /map - - Takes a hashcode and return the related contract. Typically used by backoffice interfaces. - - **Request** - - :query h_contract: hashcode of the contract we want to retrieve. - - **Return** - - :status 200 OK: - The body contains a `contract`_ corresponding to `h_contract`. - - :status 404 Not Found: - There is no contract corresponding to `h_contract`. - - ------------------------------- -The Merchant Backend HTTP API ------------------------------- - -The following API are made available by the merchant's `backend` to the merchant's `frontend`. - -.. http:post:: /contract - - Ask the backend to add some missing (mostly related to cryptography) information to the contract. - - **Request:** - -.. _proposition: - - The `proposition` that is to be sent from the frontend is a :ref:`Contract ` object - **without** the fields: - - * `exchanges` - * `auditors` - * `H_wire` - * `merchant_pub` - - The frontend may or may not provide a `instance` field in the proposition, depending on its logic. - The ``default`` instance will be used if no `instance` field is found by the backend. - - **Response** - - :status 200 OK: - The backend has successfully created the contract. It responds with an :ref:`offer `. On success, the `frontend` should pass this response verbatim to the wallet. - - :status 403 Forbidden: - The frontend used the same transaction ID twice. This is only allowed if the response from the backend was lost ("instant" replay), but to assure that frontends usually create fresh transaction IDs this is forbidden if the contract was already paid. So attempting to have the backend sign a contract for a contract that was already paid by a wallet (and thus was generated by the frontend a "long" time ago), is forbidden and results in this error. Frontends must make sure that they increment the transaction ID properly and persist the largest value used so far. - -.. http:post:: /pay - - Asks the `backend` to execute the transaction with the exchange and deposit the coins. - - **Request:** - - The `frontend` passes the :ref:`deposit permission ` - received from the wallet, and optionally adding a field named `wire_transfer_deadline`, - indicating a deadline by which he would expect to receive the bank transfer - for this deal. Note that the `wire_transfer_deadline` must be after the `refund_deadline`. - The backend calculates the `wire_transfer_deadline` by adding the `wire_transfer_delay` - value found in the configuration to the current time. - - **Response:** - - :status 200 OK: - The exchange accepted all of the coins. The body is a `PaymentResponse`_. - 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 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 of `TALER_PaymentResponsePS`_ - merchant_sig: EddsaSignature; - - // Contract's hash being signed over - h_contract: HashCode; - } - -.. 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 exchange: base URI of the exchange that made the wire transfer - :query instance: (optional) identificative token of the merchant :ref:`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 :ref:`TrackTransferResponse `. 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`_. - - - **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: identificative token for the merchant instance which is to be tracked (optional). See :ref:`instances-lab`. This information is needed because the request has to be signed by the merchant, thus we need to pick the instance's private key. - - **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/transaction - 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; - - // Array of data about coins - coins: CoinWireTransfer[]; - } - - .. _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/transaction`). - transaction_tracking_claim: TrackTransactionResponse; - - // Public key of the coin for which we got conflicting information. - coin_pub: CoinPublicKey; - - } - - -.. http:post:: /map/in - - Store a pair formed by a plain contract and its hashcode into the database. - - **Request** - - The frontend passes a `MapRequest`_ object. - - **Response** - - :status 200 OK: - The data has been successfully stored. - - :status 422 Unprocessable Entity: - The hashcode provided by the frontend does not match the contract. - -.. _MapRequest: -.. _tsref-type-MapRequest: -.. code-block:: tsref - - interface MapRequest { - - // Plain contract to be stored - contract: Contract; - - // contract's hashcode. We require this value from the frontend - // as an additional check on data integrity. - h_contract: HashCode; - } - - -.. http:get:: /map/out - - Retrieve a contract, given its hashcode. - - **Request** - - :query h_contract: hashcode of the contract to retrieve. - - **Response** - - :status 200 OK: - The body contains a `contract`_ corresponding to `h_contract`. - - :status 404 Not Found: - There is no contract corresponding to `h_contract` into the database. - -.. http:get:: /history - - Returns transactions up to some point in the past - - **Request** - - :query date: only transactions *jounger* than this parameter will be returned. It's a timestamp, given in seconds. - - **Response** - - :status 200 OK: The response is a JSON `array` of `TransactionHistory`_. - - .. _tsref-type-TransactionHistory: - .. _TransactionHistory: - .. code-block:: tsref - - interface TransactionHistory { - // transaction id - transaction_id: number; - - // Hashcode of the relevant contract - h_contract: HashCode; - - // Exchange's base URL - exchange: string; - - // Transaction's timestamp - timestamp: Timestamp; - - // Price payed for this transaction - total_amount: Amount; - } - -.. _contract: - ------------------- -Offer and Contract ------------------- - -An `offer` is a wrapper around a contract with some additional information -that is legally non-binding: - - .. _tsref-type-Offer: - .. code-block:: tsref - :name: offer - - interface Offer { - // The actual contract - contract: Contract; - - // Contract's hash, provided as a convenience. All components that do - // not fully trust the merchant must verify this field. - H_contract: HashCode ; - - // Signature over the hashcode of `contract` made by the merchant. - merchant_sig: EddsaSignature; - } - -.. note:: - When the contract is signed by the merchant or the wallet, the - signature is made over the hash of the JSON text, as the contract may - be confidential between merchant and customer and should not be - exposed to the exchange. The hashcode is generated by hashing the - encoding of the contract's JSON obtained by using the flags - ``JSON_COMPACT | JSON_PRESERVE_ORDER``, as described in the `libjansson - documentation - `_. - -The `contract` must have the following structure: - - .. _tsref-type-Contract: - .. code-block:: tsref - - interface Contract { - // Human-readable description of the whole purchase - // NOTE: still not implemented - summary: string; - - // Total price for the transaction. - // The exchange will subtract deposit fees from that amount - // before transfering it to the merchant. - amount: Amount; - - // Optional identifier chosen by the merchant, - // which allows the wallet to detect if it is buying - // a contract where it already has paid for the same - // product instance. NOTE: this information is mainly - // needed when the customer visits a shared fulfillment - // URL about a product they already paid for, so that - // the wallet can reuse the same coins used in the first - // place. - repurchase_correlation_id?: string; - - // URL that the wallet will navigate to after the customer - // confirmed purchasing the contract. Responsible for - // doing the actual payment and making available the product (if digital) - // or displaying a confirmation. - // The placeholder ${H_contract} will be replaced - // with the contract hash by wallets before navigating - // to the fulfillment URL. - fulfillment_url: string; - - // Maximum total deposit fee accepted by the merchant for this contract - max_fee: Amount; - - // 53-bit number chosen by the merchant to uniquely identify the contract. - transaction_id: number; - - // 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 - expiry: Timestamp; - - // Merchant's public key used to sign this contract; 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; - - // Which instance is participating in this contract. See `Merchant Instances `_. - // This field is optional, as the "default" instance is not forced to provide any `instance` identificator. - instance: string; - - // The hash of the merchant instance's wire details. - H_wire: HashCode; - - // 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], ... }; - } - - 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?: number; - - // The price of the product; this is the total price for the amount specified by `quantity` - price: Amount; - - // merchant's 53-bit internal identification number for the product (optional) - product_id?: number; - - // 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 URI 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; - } - - - .. _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; - } diff --git a/api/api-bank.rst b/api/api-bank.rst new file mode 100644 index 00000000..48b7075e --- /dev/null +++ b/api/api-bank.rst @@ -0,0 +1,81 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016 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 + +========= +Bank API +========= + +The following APIs are served from banks, in order to allow exchanges to +deposit funds to money recipients. A typical scenario for calling this +APIs is after a merchant has deposited coins to the exchange, and the exchange +needs to give real money to the merchant. + +------------------ +Administrative API +------------------ + +This is `local` API, meant to make the bank communicate with trusted entities, +namely exchanges. + +.. _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 + +:status 400 Bad Request: The bank replies a `BankIncomingError`_ object + +**Details:** + +.. _BankDepositRequest: +.. code-block:: tsref + + interface BankDepositRequest { + + // JSON 'amount' object. The amount the caller wants to transfer + // to the recipient's count + amount: Amount; + + // The id of this wire transfer + wtid: base32; + + // The sender's account identificator + debit_account: number; + + // The recipient's account identificator + credit_account: number; + + } + +.. _BankIncomingError: +.. code-block:: tsref + + interface BankIncomingError { + + // Human readable explanation of the failure. + reason: string + + } + +-------- +Util API +-------- + +Whenever the user wants to know the bank account number of a public account, +the following path returns a human readable HTML containing this information + + `/public-accounts/details?account=accountName` diff --git a/api/api-common.rst b/api/api-common.rst new file mode 100644 index 00000000..411f7df5 --- /dev/null +++ b/api/api-common.rst @@ -0,0 +1,705 @@ +.. + 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 +^^^^^^^ + +Amounts of currency are expressed as a JSON object with the following fields: + +.. _`tsref-type-Amount`: + +.. code-block:: tsref + + interface Amount { + // 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 { + /** + * 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 :ref:`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; + struct GNUNET_HashCode h_wire; + struct GNUNET_TIME_AbsoluteNBO timestamp; + struct GNUNET_TIME_AbsoluteNBO refund_deadline; + uint64_t transaction_id; + 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; + struct GNUNET_HashCode h_wire; + uint64_t transaction_id GNUNET_PACKED; + 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; + }; + + 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_SEPA_DETAILS || TALER_SIGNATURE_MASTER_TEST_DETAILS + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct GNUNET_HashCode h_sepa_details; + }; + + 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; + struct GNUNET_HashCode h_wire; + uint64_t transaction_id; + struct TALER_MerchantPublicKeyP merchant; + struct TALER_CoinSpendPublicKeyP coin_pub; + }; + + /** + * Format internally used for packing the detailed information + * to generate the signature for /track/transfer signatures. + */ + struct TALER_WireDepositDetailP { + struct GNUNET_HashCode h_contract; + struct GNUNET_TIME_AbsoluteNBO execution_time; + uint64_t transaction_id GNUNET_PACKED; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_AmountNBO deposit_value; + struct TALER_AmountNBO deposit_fee; + }; + + + struct TALER_WireDepositDataPS { + /** + * purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + struct TALER_AmountNBO total; + 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; + }; + + +.. _TALER_ContractPS: +.. sourcecode:: c + + struct TALER_ContractPS { + /** + * purpose.purpose = TALER_SIGNATURE_MERCHANT_CONTRACT + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + uint64_t transaction_id; + struct TALER_AmountNBO total_amount; + struct TALER_AmountNBO max_fee; + struct GNUNET_HashCode h_contract; + struct TALER_MerchantPublicKeyP merchant_pub; + }; + + 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; + struct TALER_WireTransferIdentifierRawP wtid; + struct TALER_CoinSpendPublicKeyP coin_pub; + uint64_t transaction_id; + 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 GNUNET_PACKED; + uint64_t transaction_id GNUNET_PACKED; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_MerchantPublicKeyP merchant; + uint64_t rtransaction_id GNUNET_PACKED; + struct TALER_AmountNBO refund_amount; + struct TALER_AmountNBO refund_fee; + }; diff --git a/api/api-error.rst b/api/api-error.rst new file mode 100644 index 00000000..cf107b11 --- /dev/null +++ b/api/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/api/api-exchange.rst b/api/api-exchange.rst new file mode 100644 index 00000000..7f1a1516 --- /dev/null +++ b/api/api-exchange.rst @@ -0,0 +1,1527 @@ +.. + 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 + +============================= +The Exchange RESTful JSON API +============================= + +The API specified here follows the :ref:`general conventions ` +for all details not specified in the individual requests. The :ref:`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. + + **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 { + // EdDSA master public key of the exchange, used to sign entries in `denoms` and `signkeys` + master_public_key: EddsaPublicKey; + + // Denomination offered by this exchange. + denoms: Denom[]; + + // 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. + + 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 { + // The key is a supported method (i.e. "sepa" or "test"). + // The value is a method-specific JSON object with account details + // (i.e. IBAN number, owner name, bank address, etc.). + // The value objects may also contain signatures (if applicable). + // + // A single /wire response can contain an arbitrary number of these + // string-object pairs. However, the keys must be unique. + string: Object; + } + + Possible encodings for the objects are right now the following: + + .. _WireTestResponse: + .. _tsref-type-WireTestResponse: + .. code-block:: tsref + + interface WireTestResponse { + // Mandatory indicator that this is a TEST wire response. + type: "test"; + + // Account number at the bank + account_number: number; + + // URI of the bank + bank_uri: string; + + // Name of the account's owner + name: string; + + // Salt used to sign, `base32`_ encoded + salt: string; + + // Signaure of `TALER_MasterWireDetailsPS`_ with purpose TALER_SIGNATURE_MASTER_TEST_DETAILS + // Note that the `h_sepa_details` field of `TALER_MasterWireDetailsPS`_ is computed + // by concatenating all of the above fields (in the same order they appear) and then + // by hashing the obtained concatenation. + sig: EddsaSignature; + } + + .. _WireSepaResponse: + .. _tsref-type-WireSepaResponse: + .. code-block:: tsref + + interface WireSepaResponse { + // Mandatory indicator that this is a SEPA wire response. + type: "sepa"; + + // Legal name of the owner of the account + receiver_name: string; + + // IBAN account number. + iban: string; + + // BIC of the bank. + bic: string; + + // Signaure of `TALER_MasterWireDetailsPS`_ with purpose TALER_SIGNATURE_MASTER_SEPA_DETAILS + // Note that the `h_sepa_details` field of `TALER_MasterWireDetailsPS`_ is computed + // by concatenating all of the above fields (in the same order they appear) and then + // by hashing the obtained concatenation. + 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" or "DEPOSIT" + type: string; + + // The amount that was withdrawn or deposited. + amount: Amount; + + // Sender account details, only present if type is "DEPOSIT". + sender_account_details?: any; + + // Transfer details uniquely identifying the transfer, only present if type is "DEPOSIT". + transfer_details?: any; + + // `base32`_ encoding of `TALER_WithdrawRequestPS`_ with purpose TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW. This field appears only if `type` is "WITHDRAW". + details?: string; + + // Signature of `TALER_WithdrawRequestPS`_ created with the `reserves's private key `_. Only present if type is "WITHDRAW". + signature?: EddsaSignature; + } + + +.. 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 { + // Denomination public key (RSA), specifying the type of coin the client + // would like the exchange to create. + denom_pub: RsaPublicKey; + + // 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: + 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. + 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: HashCode; + + // `coin's public key `_, both ECDHE and EdDSA. + coin_pub: CoinPublicKey; + + // denomination RSA key with which the coin is signed + denom_pub: RsaPublicKey; + + // 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 + timestamp: Timestamp; + + // indicative time by which the exchange undertakes to transfer the funds to + // the merchant, in case of successful payment. + pay_deadline: Timestamp; + + // 64-bit transaction id for the transaction between merchant and customer + transaction_id: number; + + // 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" or "melt" or "refund" + 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; + + // `base32`_ binary encoding of the transaction data as a + // `TALER_DepositRequestPS`_ or `TALER_RefreshMeltCoinAffirmationPS`_ + // or `TALER_RefundRequestPS`_ + details: string; + + // `EdDSA Signature `_ of what we got in `details`. + // Note that in the case of a 'refund', the signature is made with + // the `public key of the merchant `_, and not `that of the coin `_ + signature: EddsaSignature; + } + +---------- +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 { + // Array of `n` new denominations to order. + new_denoms: RsaPublicKey[]; + + // Information about coin being melted. + melt_coin: MeltCoin; + + // The outer dimension of the 2d array has `kappa` entries + // for the cut-and-choose protocol. + // The inner array contains `n` entries with blinded coins, + // matching the respective entries in `new_denoms`. + coin_evs: CoinEnvelope[][]; + + // `kappa` transfer public keys (ephemeral ECDHE keys) + transfer_pubs: EddsaPublicKey[]; + + } + + 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`. The `melt_coin` field is a list of JSON + objects with the following fields: + + + .. _tsref-type-MeltCoin: + .. code-block:: tsref + + interface MeltCoin { + // `Coin public key `_, uniquely identifies the coin + coin_pub: string; + + // The denomination public key allows the exchange to determine total coin value. + denom_pub: RsaPublicKey; + + // Signature over the `coin public key `_ by the denomination. + denom_sig: RsaSignature; + + // Signature by the `coin `_ over the session public key. + 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; + } + + 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. + + + .. _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. + Request body contains a JSON object with the following fields: + + + :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`_. + + + + .. code-block:: tsref + + interface RevealRequest { + // Hash over most of the arguments to the /exchange/melt step. Used to + // identify the corresponding melt operation. For details on which elements + // must be hashed in which order, please consult the source code of the exchange + // reference implementation. + session_hash: HashCode; + + // Array of `kappa - 1` ECDHE transfer private keys. + // The exchange will use those to decrypt the transfer secrets, + // and then decrypt the private keys and blinding factors + // of the coins to be generated and check all this against the commitments. + transfer_privs: EddsaPrivateKey[]; + } + + + .. _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; + + // Signature of the coin over the melting operation. + coin_sig: EddsaSignature; + + // Coin that we failed to successfully melt. + coin_pub: EddsaPublicKey; + + // Amount of the value of the coin to be melted in the refresh session. + melt_amount_with_fee: Amount; + + // Fee that was due for the melting for the coin. + melt_fee: Amount; + + // Denomination keys to be used for the coins to be withdrawn. + newcoin_infos: RsaPublicKey[]; + + // Array of blinded coins to be withdrawn. Same length as + // `newcoin_infos`. + commit_infos: CoinEnvelope[]; + + // Transfer public key at index `gamma`. + gamma_tp: EddsaPublicKey; + + // Specific `gamma` value chosen by the exchange. + gamma: number; + + } + + + .. _tsref-type-LinkInfo: + .. code-block:: tsref + + interface LinkInfo { + // the transfer ECDHE public key + transfer_pub: EddsaPublicKey; + + } + + .. _tsref-type-CommitInfo: + .. code-block:: tsref + + interface CommitInfo { + coin_ev: BlindedRsaSignature; + + } + + +.. 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 + // decrypt the `secret_enc` in combination with the private key of + // `coin_pub`. + transfer_pub: EcdhePublicKey; + + // ECDHE-encrypted link secret that, once decrypted, can be used to + // decrypt/unblind the `new_coins`. + secret_enc: Base32; + + // 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; + } + + + + +----------------------- +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; + + // 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: HashCode; + + // 64-bit transaction id for the transaction between merchant and + // customer + transaction_id: number; + + // 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: HashCode; + + // coin's public key, both ECDHE and EdDSA. + coin_pub: CoinPublicKey; + + // 64-bit transaction id for the transaction between merchant and customer + transaction_id: number; + + // 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 +------- + + .. note:: + + Refunds are currently not implemented (#3641), this documentation is thus a bit preliminary and may still change. + +.. _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: HashCode; + + // coin's public key, both ECDHE and EdDSA. + coin_pub: CoinPublicKey; + + // 64-bit transaction id of the original transaction between merchant and customer + transaction_id: number; + + // 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; + } + +------------------------------ +Administrative API: Key update +------------------------------ + + .. note:: + + This is not yet implemented (no bug number yet, as we are not sure we will + implement this; for now, adding new files to the directory and sending a + signal to the exchange process seems to work fine). + +New denomination and signing keys can be uploaded to the exchange via the +HTTP interface. It is, of course, only possible to upload keys signed +by the exchange's master key. Furthermore, this API should probably only +be used via loopback, as we want to protect the private keys from +interception. + +.. http:POST:: /admin/add/denomination_key + + Upload a new denomination key. + + **Request:** + + .. code-block:: tsref + + { + // Public part of the denomination key + denom_info: any: + + // Private RSA key + denom_priv: RsaPrivateKey; + } + + +.. http:POST:: /admin/add/sign_key + + Upload a new signing key. + + **Request:** + + .. code-block:: tsref + + { + // Public part of the signing key + sign_info: any; + + // Private EdDSA key + sign_priv: EddsaPrivateKey; + } + +.. _add-incoming: + +------------------------------------- +Administrative API: Bank transactions +------------------------------------- + +.. http:POST:: /admin/add/incoming + + Notify exchange of an incoming transaction to fill a reserve. + + **Request:** + + .. code-block:: tsref + + { + // Reserve public key + reserve_pub: EddsaPublicKey; + + // Amount transferred to the reserve + amount: Amount; + + // When was the transaction executed + execution_date: Timestamp; + + // Sender's wire account details, so that the exchange knows from whom the + // money comes from (and can possibly refund it). The details + // given here must be in a wire format supported by the exchange. + sender_account_details: any; + + // The wire details given here should include an unique identifier + // for each transaction. The exchange will check that the details + // given are unique, and if the wire details are identical to previous + // wire details will treat the request as a duplicate and not actually + // do any update. This is true even if the amount or execution date + // differs. + // + // Note that the exchange does not interpret these details in any + // way, other than for "being unique". They are stored for diagnostics + // and auditing. + transfer_details: any; + } + + **Response:** + + :status 200: + The operation succeeded. The body is an `AddIncomingResponse`_ object. + :status 403: + the client is not permitted to add incoming transactions. The request may + be disallowed by the configuration in general or restricted to certain IP + addresses (i.e. loopback-only). + + + .. _AddIncomingResponse: + .. code-block:: tsref + + interface AddIncomingResponse { + // The string constant `NEW` or `DUP` to indicate whether the transaction + // was truly added to the DB or whether it already existed in the DB + status: string; + } + +.. http:POST:: /admin/add/outgoing + + Notify exchange about the completion of an outgoing transaction satisfying a + /deposit request. In the future, this will allow merchants to obtain details + about the /deposit requests they send to the exchange. + + .. note:: + + This is not yet implemented (no bug number yet either). + + **Request:** + + .. code-block:: tsref + + { + coin_pub: CoinPublicKey; + + // Amount transferred to the merchant + amount: Amount; + + // Transaction identifier in the wire details + transaction: number; + + // `Wire transaction details `_, as originally specified by the merchant + wire: Object; + } + + **Response** + + :status 200: The request was successful. + :status 403: the client is not permitted to add outgoing transactions + + If the request was successful, the response has the following format: + + .. code-block:: tsref + + { + // The string constant `NEW` or `DUP` to indicate whether the transaction + // was truly added to the DB or whether it already existed in the DB + status: string; + } + +------------ +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/api-merchant.rst b/api/api-merchant.rst new file mode 100644 index 00000000..9eccc2fa --- /dev/null +++ b/api/api-merchant.rst @@ -0,0 +1,699 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016 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 + @author Florian Dold + @author Christian Grothoff + +.. _merchant-api: + +============ +Merchant API +============ + +Before reading the API reference documentation, see the :ref:`merchant architecture` and :ref:`payprot` + +--------------------- +The Frontend HTTP API +--------------------- + +This frontend API is non-normative, and only gives an example of what a typical frontend API would look like. + +.. http:get:: contract_url + + Requesting this URL generates a contract, typically with a new (and unique) transaction id. + + **Request:** + + The request depends entirely on the merchant implementation. + + **Response** + + :status 200 OK: The request was successful. The body contains an :ref:`Offer `. + :status 400 Bad Request: Request not understood. + :status 500 Internal Server Error: + In most cases, some error occurred while the backend was generating the + contract. For example, it failed to store it into its database. + +.. _pay: +.. http:post:: pay_url + + + Send the deposit permission to the merchant. The client should POST a `DepositPermission`_ + object. If the payment was processed successfully by the merchant, this URL will set session + state that allows the fulfillment URL to show the final product. + + .. _DepositPermission: + .. code-block:: tsref + + interface DepositPermission { + // the hashed `wire details `_ of this merchant. + // The wallet takes this value as-is from the contract + H_wire: HashCode; + + // `base32`_ encoded `TALER_ContractPS`_. The wallet can choose whether + // to take this value obtained from the field `h_contract`, + // or regenerating one starting from the values it gets within the contract + H_contract: HashCode; + + // a 53-bit number corresponding to the contract being agreed on + transaction_id: number; + + // total amount being paid as per the contract (the sum of the amounts from the `coins` may be larger to cover deposit fees not covered by the merchant) + total_amount: Amount; + + // maximum fees merchant agreed to cover as per the contract + max_fee: Amount; + + // The `merchant instance `_ which is going to receive the final wire transfer. + instance: string; + + // Signature of `TALER_ContractPS`_ + merchant_sig: EddsaSignature; + + // a timestamp of this deposit permission. It equals just the contract's timestamp + timestamp: Timestamp; + + // Deadline for the customer to be refunded for this purchase + refund_deadline: Timestamp; + + // Deadline for the customer to pay for this purchase. Note that is up to the frontend + // to make sure that this value matches the one the backend signed over when the contract + // was generated. The frontend should never verify if the payment is still on time, + // because when payments are replayed it is expxectable that this deadline is expired, + // and only the backend can detect if a payment is a reply or not. + pay_deadline: Timestamp; + + // the chosen exchange's base URL + exchange: string; + + // the coins used to sign the contract + coins: DepositedCoin[]; + + } + + .. _`tsref-type-DepositedCoin`: + + .. code-block:: tsref + + interface DepositedCoin { + // the amount this coin is paying for + amount: Amount; + + // coin's public key + coin_pub: RsaPublicKey; + + // denomination key + denom_pub: RsaPublicKey; + + // exchange's signature over this `coin's public key `_ + ub_sig: RsaSignature; + + // Signature of `TALER_DepositRequestPS`_ + coin_sig: EddsaSignature; + } + + **Success Response:** + + :status 301 Redirection: the merchant should redirect the client to his fullfillment page, where the good outcome of the purchase must be shown to the user. + + **Failure Responses:** + + The error codes and data sent to the wallet are a mere copy of those gotten from the exchange when attempting to pay. The section about :ref:`deposit ` explains them in detail. + + +.. http:post:: fulfillment_url + + Returns a cooperative merchant page (called the execution page) that will + send the ``taler-execute-payment`` to the wallet and react to failure or + success of the actual payment. ``fulfillment_url`` is included in the `contract`_. + Furthermore, :ref:`payprot` documents the payment protocol between wallets and + merchants. + + The wallet will inject an ``XMLHttpRequest`` request to the merchant's + ``$pay_url`` in the context of the execution page. This mechanism is + necessary since the request to ``$pay_url`` must be made from the merchant's + origin domain in order to preserve information (e.g. cookies, origin header). + +.. http:get:: /history + + Return a list of fulfilled contracts. Typically used by backoffice interfaces. + + **Request** + + :query days: a number indicating that we request contracts from now up to `days` days ago. + + **Response** + + :status 200 OK: The response is a JSON array of `TransactionHistory`_. + +.. http:get:: /map + + Takes a hashcode and return the related contract. Typically used by backoffice interfaces. + + **Request** + + :query h_contract: hashcode of the contract we want to retrieve. + + **Return** + + :status 200 OK: + The body contains a `contract`_ corresponding to `h_contract`. + + :status 404 Not Found: + There is no contract corresponding to `h_contract`. + + +------------------------------ +The Merchant Backend HTTP API +------------------------------ + +The following API are made available by the merchant's `backend` to the merchant's `frontend`. + +.. http:post:: /contract + + Ask the backend to add some missing (mostly related to cryptography) information to the contract. + + **Request:** + +.. _proposition: + + The `proposition` that is to be sent from the frontend is a :ref:`Contract ` object + **without** the fields: + + * `exchanges` + * `auditors` + * `H_wire` + * `merchant_pub` + + The frontend may or may not provide a `instance` field in the proposition, depending on its logic. + The ``default`` instance will be used if no `instance` field is found by the backend. + + **Response** + + :status 200 OK: + The backend has successfully created the contract. It responds with an :ref:`offer `. On success, the `frontend` should pass this response verbatim to the wallet. + + :status 403 Forbidden: + The frontend used the same transaction ID twice. This is only allowed if the response from the backend was lost ("instant" replay), but to assure that frontends usually create fresh transaction IDs this is forbidden if the contract was already paid. So attempting to have the backend sign a contract for a contract that was already paid by a wallet (and thus was generated by the frontend a "long" time ago), is forbidden and results in this error. Frontends must make sure that they increment the transaction ID properly and persist the largest value used so far. + +.. http:post:: /pay + + Asks the `backend` to execute the transaction with the exchange and deposit the coins. + + **Request:** + + The `frontend` passes the :ref:`deposit permission ` + received from the wallet, and optionally adding a field named `wire_transfer_deadline`, + indicating a deadline by which he would expect to receive the bank transfer + for this deal. Note that the `wire_transfer_deadline` must be after the `refund_deadline`. + The backend calculates the `wire_transfer_deadline` by adding the `wire_transfer_delay` + value found in the configuration to the current time. + + **Response:** + + :status 200 OK: + The exchange accepted all of the coins. The body is a `PaymentResponse`_. + 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 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 of `TALER_PaymentResponsePS`_ + merchant_sig: EddsaSignature; + + // Contract's hash being signed over + h_contract: HashCode; + } + +.. 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 exchange: base URI of the exchange that made the wire transfer + :query instance: (optional) identificative token of the merchant :ref:`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 :ref:`TrackTransferResponse `. 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`_. + + + **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: identificative token for the merchant instance which is to be tracked (optional). See :ref:`instances-lab`. This information is needed because the request has to be signed by the merchant, thus we need to pick the instance's private key. + + **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/transaction + 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; + + // Array of data about coins + coins: CoinWireTransfer[]; + } + + .. _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/transaction`). + transaction_tracking_claim: TrackTransactionResponse; + + // Public key of the coin for which we got conflicting information. + coin_pub: CoinPublicKey; + + } + + +.. http:post:: /map/in + + Store a pair formed by a plain contract and its hashcode into the database. + + **Request** + + The frontend passes a `MapRequest`_ object. + + **Response** + + :status 200 OK: + The data has been successfully stored. + + :status 422 Unprocessable Entity: + The hashcode provided by the frontend does not match the contract. + +.. _MapRequest: +.. _tsref-type-MapRequest: +.. code-block:: tsref + + interface MapRequest { + + // Plain contract to be stored + contract: Contract; + + // contract's hashcode. We require this value from the frontend + // as an additional check on data integrity. + h_contract: HashCode; + } + + +.. http:get:: /map/out + + Retrieve a contract, given its hashcode. + + **Request** + + :query h_contract: hashcode of the contract to retrieve. + + **Response** + + :status 200 OK: + The body contains a `contract`_ corresponding to `h_contract`. + + :status 404 Not Found: + There is no contract corresponding to `h_contract` into the database. + +.. http:get:: /history + + Returns transactions up to some point in the past + + **Request** + + :query date: only transactions *jounger* than this parameter will be returned. It's a timestamp, given in seconds. + + **Response** + + :status 200 OK: The response is a JSON `array` of `TransactionHistory`_. + + .. _tsref-type-TransactionHistory: + .. _TransactionHistory: + .. code-block:: tsref + + interface TransactionHistory { + // transaction id + transaction_id: number; + + // Hashcode of the relevant contract + h_contract: HashCode; + + // Exchange's base URL + exchange: string; + + // Transaction's timestamp + timestamp: Timestamp; + + // Price payed for this transaction + total_amount: Amount; + } + +.. _contract: + +------------------ +Offer and Contract +------------------ + +An `offer` is a wrapper around a contract with some additional information +that is legally non-binding: + + .. _tsref-type-Offer: + .. code-block:: tsref + :name: offer + + interface Offer { + // The actual contract + contract: Contract; + + // Contract's hash, provided as a convenience. All components that do + // not fully trust the merchant must verify this field. + H_contract: HashCode ; + + // Signature over the hashcode of `contract` made by the merchant. + merchant_sig: EddsaSignature; + } + +.. note:: + When the contract is signed by the merchant or the wallet, the + signature is made over the hash of the JSON text, as the contract may + be confidential between merchant and customer and should not be + exposed to the exchange. The hashcode is generated by hashing the + encoding of the contract's JSON obtained by using the flags + ``JSON_COMPACT | JSON_PRESERVE_ORDER``, as described in the `libjansson + documentation + `_. + +The `contract` must have the following structure: + + .. _tsref-type-Contract: + .. code-block:: tsref + + interface Contract { + // Human-readable description of the whole purchase + // NOTE: still not implemented + summary: string; + + // Total price for the transaction. + // The exchange will subtract deposit fees from that amount + // before transfering it to the merchant. + amount: Amount; + + // Optional identifier chosen by the merchant, + // which allows the wallet to detect if it is buying + // a contract where it already has paid for the same + // product instance. NOTE: this information is mainly + // needed when the customer visits a shared fulfillment + // URL about a product they already paid for, so that + // the wallet can reuse the same coins used in the first + // place. + repurchase_correlation_id?: string; + + // URL that the wallet will navigate to after the customer + // confirmed purchasing the contract. Responsible for + // doing the actual payment and making available the product (if digital) + // or displaying a confirmation. + // The placeholder ${H_contract} will be replaced + // with the contract hash by wallets before navigating + // to the fulfillment URL. + fulfillment_url: string; + + // Maximum total deposit fee accepted by the merchant for this contract + max_fee: Amount; + + // 53-bit number chosen by the merchant to uniquely identify the contract. + transaction_id: number; + + // 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 + expiry: Timestamp; + + // Merchant's public key used to sign this contract; 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; + + // Which instance is participating in this contract. See `Merchant Instances `_. + // This field is optional, as the "default" instance is not forced to provide any `instance` identificator. + instance: string; + + // The hash of the merchant instance's wire details. + H_wire: HashCode; + + // 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], ... }; + } + + 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?: number; + + // The price of the product; this is the total price for the amount specified by `quantity` + price: Amount; + + // merchant's 53-bit internal identification number for the product (optional) + product_id?: number; + + // 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 URI 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; + } + + + .. _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; + } diff --git a/api/conf.py b/api/conf.py new file mode 100644 index 00000000..8db3f93b --- /dev/null +++ b/api/conf.py @@ -0,0 +1,285 @@ +""" + 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 Lesser 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 +""" +# -*- coding: utf-8 -*- +# +# neuro documentation build configuration file, created by +# sphinx-quickstart on Sat May 31 13:11:06 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = '1.3' + +sys.path.append(os.path.abspath('exts')) + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'tsref', + 'sphinx.ext.todo', + 'sphinx.ext.pngmath', + 'sphinxcontrib.httpdomain' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Taler' +copyright = u'2014, 2015, 2016 Florian Dold, Benedikt Muller, Sree Harsha Totakura, Christian Grothoff, Marcello Stanisci (GPLv3+ or GFDL 1.3+)' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.1' +# The full version, including alpha/beta/rc tags. +release = '0.1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'neurodoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'taler.tex', u'Taler Documentation', + u'F. Dold, B. Muller, S. H. Totakura, C. Grothoff', + 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'neuro', u'neuro Documentation', + [u'F. Dold, B. Muller, S. H. Totakura, C. Grothoff'], + 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'neuro', u'neuro Documentation', + u'F. Dold, B. Muller, S. H. Totakura, C. Grothoff', + 'neuro', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff --git a/api/exts/__pycache__/tsref.cpython-35.pyc b/api/exts/__pycache__/tsref.cpython-35.pyc new file mode 100644 index 00000000..f8474d57 Binary files /dev/null and b/api/exts/__pycache__/tsref.cpython-35.pyc differ diff --git a/api/exts/tsref.py b/api/exts/tsref.py new file mode 100644 index 00000000..8187f67f --- /dev/null +++ b/api/exts/tsref.py @@ -0,0 +1,233 @@ +""" + This file is part of GNU TALER. + Copyright (C) 2014, 2015 GNUnet e.V. and INRIA + TALER 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, 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 +""" + +""" +This extension adds a new lexer "tsref" for TypeScript, which +allows reST-style links inside comments (`LinkName`_), +and semi-automatically adds links to the definition of types. + +For type TYPE, a reference to tsref-type-TYPE is added. + +Known bugs and limitations: + - The way the extension works right now interferes wiht + Sphinx's caching, the build directory should be cleared + before every build. +""" + + +from pygments.util import get_bool_opt +from pygments.token import Name, Comment, Token, _TokenType +from pygments.filter import Filter +from sphinx.highlighting import PygmentsBridge +from sphinx.builders.html import StandaloneHTMLBuilder +from sphinx.pygments_styles import SphinxStyle +from pygments.formatters import HtmlFormatter +from docutils import nodes +from docutils.nodes import make_id +import re + + +_escape_html_table = { + ord('&'): u'&', + ord('<'): u'<', + ord('>'): u'>', + ord('"'): u'"', + ord("'"): u''', +} + + +class LinkingHtmlFormatter(HtmlFormatter): + def __init__(self, **kwargs): + super(LinkingHtmlFormatter, self).__init__(**kwargs) + self._builder = kwargs['_builder'] + + def _fmt(self, value, tok): + cls = self._get_css_class(tok) + href = tok_getprop(tok, "href") + caption = tok_getprop(tok, "caption") + content = caption if caption is not None else value + if href: + value = '%s' % (href, content) + if cls is None or cls == "": + return value + return '%s' % (cls, value) + + def _format_lines(self, tokensource): + """ + Just format the tokens, without any wrapping tags. + Yield individual lines. + """ + lsep = self.lineseparator + escape_table = _escape_html_table + + line = '' + for ttype, value in tokensource: + link = get_annotation(ttype, "link") + + parts = value.translate(escape_table).split('\n') + + if len(parts) == 0: + # empty token, usually should not happen + pass + elif len(parts) == 1: + # no newline before or after token + line += self._fmt(parts[0], ttype) + else: + line += self._fmt(parts[0], ttype) + yield 1, line + lsep + for part in parts[1:-1]: + yield 1, self._fmt(part, ttype) + lsep + line = self._fmt(parts[-1], ttype) + + if line: + yield 1, line + lsep + + +class MyPygmentsBridge(PygmentsBridge): + def __init__(self, builder, trim_doctest_flags): + self.dest = "html" + self.trim_doctest_flags = trim_doctest_flags + self.formatter_args = {'style': SphinxStyle, '_builder': builder} + self.formatter = LinkingHtmlFormatter + + +class MyHtmlBuilder(StandaloneHTMLBuilder): + name = "html-linked" + def init_highlighter(self): + if self.config.pygments_style is not None: + style = self.config.pygments_style + elif self.theme: + style = self.theme.get_confstr('theme', 'pygments_style', 'none') + else: + style = 'sphinx' + self.highlighter = MyPygmentsBridge(self, self.config.trim_doctest_flags) + + def write_doc(self, docname, doctree): + self._current_docname = docname + super(MyHtmlBuilder, self).write_doc(docname, doctree) + + +def get_annotation(tok, key): + if not hasattr(tok, "kv"): + return None + return tok.kv.get(key) + + +def copy_token(tok): + new_tok = _TokenType(tok) + # This part is very fragile against API changes ... + new_tok.subtypes = set(tok.subtypes) + new_tok.parent = tok.parent + return new_tok + + +def tok_setprop(tok, key, value): + tokid = id(tok) + e = token_props.get(tokid) + if e is None: + e = token_props[tokid] = (tok, {}) + _, kv = e + kv[key] = value + + +def tok_getprop(tok, key): + tokid = id(tok) + e = token_props.get(tokid) + if e is None: + return None + _, kv = e + return kv.get(key) + + +link_reg = re.compile(r"`([^`<]+)\s*(?:<([^>]+)>)?\s*`_") + +# Map from token id to props. +# Properties can't be added to tokens +# since they derive from Python's tuple. +token_props = {} + + +class LinkFilter(Filter): + def __init__(self, app, **options): + self.app = app + Filter.__init__(self, **options) + + def filter(self, lexer, stream): + id_to_doc = self.app.env.domaindata.get("_tsref", {}) + for ttype, value in stream: + if ttype in Token.Keyword.Type: + defname = make_id('tsref-type-' + value); + t = copy_token(ttype) + if defname in id_to_doc: + docname = id_to_doc[defname] + href = self.app.builder.get_target_uri(docname) + "#" + defname + tok_setprop(t, "href", href) + + yield t, value + elif ttype in Token.Comment: + last = 0 + for m in re.finditer(link_reg, value): + pre = value[last:m.start()] + if pre: + yield ttype, pre + t = copy_token(ttype) + x1, x2 = m.groups() + if x2 is None: + caption = x1.strip() + id = make_id(x1) + else: + caption = x1.strip() + id = make_id(x2) + if id in id_to_doc: + docname = id_to_doc[id] + href = self.app.builder.get_target_uri(docname) + "#" + id + tok_setprop(t, "href", href) + tok_setprop(t, "caption", caption) + else: + self.app.builder.warn("unresolved link target in comment: " + id) + yield t, m.group(1) + last = m.end() + post = value[last:] + if post: + yield ttype, post + else: + yield ttype, value + + + +def remember_targets(app, doctree): + docname = app.env.docname + id_to_doc = app.env.domaindata.get("_tsref", None) + if id_to_doc is None: + id_to_doc = app.env.domaindata["_tsref"] = {} + for node in doctree.traverse(): + if not isinstance(node, nodes.Element): + continue + ids = node.get("ids") + if ids: + for id in ids: + id_to_doc[id] = docname + + +def setup(app): + from sphinx.highlighting import lexers + from pygments.lexers import TypeScriptLexer + from pygments.token import Name + from pygments.filters import NameHighlightFilter + lexer = TypeScriptLexer() + lexer.add_filter(LinkFilter(app)) + app.add_lexer('tsref', lexer) + app.add_builder(MyHtmlBuilder) + app.connect("doctree-read", remember_targets) diff --git a/api/global_licensing.rst b/api/global_licensing.rst new file mode 100644 index 00000000..7a5e8226 --- /dev/null +++ b/api/global_licensing.rst @@ -0,0 +1,215 @@ +=========================== +Taler licensing information +=========================== + +This file gives an overview of all Taler component's licensing and of +runtime dependencies thereof. For "component" here is meant a set of +source files which can be retrieved from a single repository. If +components consist of sources under different licensing regimes, i.e. +because we want to enable third party developments to easily integrate +with Taler, those are described as well. + +All components are generally released under Lesser GPL, GPL or Affero +GPL. The main strategy is for libraries that third parties may need +to integrate with Taler to be under LGPL, standalone binaries and +testcases to be under GPL, and Web servers implementing Web services +to be under AGPL. + ++++++++++++++++++++++++++ +API (git://taler.net/api) ++++++++++++++++++++++++++ + +The specification has been jointly developed by INRIA and by individuals +being under the juridical subject called 'GNUnet e.V.'. For each source +file, the header indicated whose is holding the copyright, since some +parts have been taken "verbatim" from the GNUnet e.V. foundation, and +some other have been developed at INRIA "ex novo". + +Generally, GNU GPLv3 license is used for them; see COPYING.GPL. + + +-------------------- +Runtime dependencies +-------------------- +This component has no runtime dependencies as it is supposed to generate +HTML. + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++ +Firefox/Android/Python Wallet (git://taler.net/wallet) +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +This project includes contributions from INRIA and GNUnet +e.V. developers. Please refer to each source file to obtain +information about the copyright holder. The GNU GPLv3 is used as the +license for Wallets. Some components may be under the LGPL. + +-------------------- +Runtime dependencies +-------------------- + +The following list encompasses all the runtime dependencies for this +project, and gives the copyright holder for each of them: + +* libgnunetutil: GPLv3+, GNUnet e.V. +* libgnunetjson: GPLv3+, GNUnet e.V. +* libgcrypt: LGPL, Free Software Foundation +* libunistring: LGPL, Free Software Foundation +* Python: Python Software Foundation License, LGPL-Compatible, Python Software Foundation +* Mozilla Firefox: Mozilla Public License, LGPL-Compatible, Mozilla Foundation + + ++++++++++++++++++++++++++++++++++++++++++++++++++++ +WebExtensions Wallet (git://taler.net/wallet-webex) ++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The TypeScript code was developed 100% at INRIA, but the project +involves compiling libgnunetutil and libtalerutil to JavaScript, and +thus depends on software from GNUnet e.V. + +Each source carries its own copyright holder(s), but it is generally +licensed under GPLv3+. + +-------------------- +Runtime dependencies +-------------------- + +The following list encompasses all the runtime dependencies for this +project, and gives the copyright holder for each of them: + +* libgnunetutil: GPLv3+, GNUnet e.V. +* libgnunetjson: GPLv3+, GNUnet e.V. +* libgcrypt: LGPL, Free Software Foundation +* libunistring: LGPL, Free Software Foundation + +Note that these dependencies are compiled into the extension and do +not appear as separate binary files. + + ++++++++++++++++++++++++++++++++++++ +Merchant (git://taler.net/merchant) ++++++++++++++++++++++++++++++++++++ + +This project contains code under two different licenses, and whose +copyright is held by INRIA and/or GNUnet e.V.. Please refer to each +source file to know which party holds the copyright. + +Source files are located in the following directories: + +* src/lib/ +* src/backend/ +* src/backenddb/ +* src/include/ +* src/tests/ +* examples/blog/ +* examples/shop/ +* copylib/ + +In examples/blog/articles/ we included a book by Richard Stallman. +It comes with its own permissive license (see COPYING in the +directory). + + +The merchant's backend (i.e. all the code in src/backend/) is under +the GNU Affero GPL as it depends on libgnunetutil. Note that the use +of the Affero GPL has little impact as the backend is not supposed to +be directly accessible to the Internet). The license for this code is +in COPYING.GPL and COPYING.AGPL. + +The merchant's frontend logic (i.e. JavaScript interacting with +the wallet, sample code for a shop) is under the GNU LGPL (but +we may choose to change this to be in the public domain or +BSD-licensed if necessary; the code is so short that there is +anyway the question whether it is copyrightable). Under this same +license, it comes the merchant library (src/lib/) as it can be linked +with more diverse licensed software. The license text for this code +is in COPYING.LGPL. + + + +-------------------- +Runtime dependencies +-------------------- + +The following list encompasses all the runtime dependencies for this +project, and gives the copyright holder for each of them: + +* libjansson: MIT License, AGPL- and LGPL-Compatible, owned by Petri Lehtinen and other individuals +* libgcrypt: LGPL, owned by Free Software Foundation +* postgresql: PostgreSQL License, AGPL- and LGPL-Compatible, owned by The PostgreSQL Global Development Group +* libgnunetutil (in all of its variants): GPLv3+, owned by GNUnet e.V. +* PHP: PHP License, AGPL- and LGPL-Compatible, owned by The PHP Group + ++++++++++++++++++++++++++++ +Bank (git://taler.net/bank) ++++++++++++++++++++++++++++ + +--------- +Licensing +--------- + +This project has been developed by INRIA. For each source file, the +header indicated whose is holding the copyright. The licensing plan +for the bank is to use the Affero GPLv3+. + +Source files of interest are located in the following directories: +(The repository holds also scaffolded files autogenerated by Django, +which do not have legal significance in this context.) + +* TalerBank/Bank/ +* TalerBank/Bank/templates/ +* TalerBank/my-static/ +* website/ + +-------------------- +Runtime dependencies +-------------------- + +The following list encompasses all the runtime dependencies for this +project, and gives the copyright holder for each of them: + +* Django: BSD License, AGPL-Compatible, owned by Django Software Foundation +* validictory: BSD License, AGPL-Compatible, owned by James Turk +* django-simple-math-captcha: Apache Software License, LGPL-Compatible (FIXME), Brandon Taylor +* requests: Apache2 License, AGPL-Compatible, owned by Kenneth Reitz +* Python: Python Software Foundation License, AGPL-Compatible, Python Software Foundation +* PHP: PHP License, AGPL-Compatible, owned by The PHP Group + + +.. _exchange-repo: + ++++++++++++++++++++++++++++++++++++ +Exchange (git://taler.net/exchange) ++++++++++++++++++++++++++++++++++++ + +This component is based on code initially developed in Munich for +GNUnet e.V. Most recent improvements and maintenance has been done at +Inria. The copyright is thus shared between both institutions. + +The licensing for exported libraries to access the exchange is LGPL, +the exchange itself is under AGPL, and testcases and standalone +binaries are under GPL. + + +-------------------- +Runtime dependencies +-------------------- + +The following list encompasses all the runtime dependencies for this +project, and gives the copyright holder for each of them: + +* libjansson: MIT License, AGPL- and LGPL-Compatible, owned by Petri Lehtinen and other individuals +* libgcrypt: LGPL, owned by Free Software Foundation +* postgresql: PostgreSQL License, AGPL- and LGPL-Compatible, owned by The PostgreSQL Global Development Group +* libgnunetutil (in all of its variants): GPLv3+, owned by GNUnet e.V. +* libgnunetjson: GPLv3+, GNUnet e.V. + + ++++++++++++++++++++++++++++++++++++++++++ +Web includes (git://taler.net/web-common) ++++++++++++++++++++++++++++++++++++++++++ + +All copyright owned by INRIA (but questionable whether creativity +threshold for copyright is even met). + +Sources are licensed under the GNU LGPL. diff --git a/api/index.rst b/api/index.rst new file mode 100644 index 00000000..01724fdf --- /dev/null +++ b/api/index.rst @@ -0,0 +1,89 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016 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 + +GNU Taler Documentation +======================= + +We are building an anonymous, taxable payment system using modern +cryptography. Customers will use traditional money transfers to send +money to a digital Exchange and in return receive (anonymized) digital +cash. Customers can use this digital cash to anonymously pay +Merchants. Merchants can redeem the digital cash for traditional +money at the digital Exchange. As Merchants are not anonymous, they can +be taxed, enabling income or sales taxes to be withheld by the state +while providing anonymity for Customers. + +Cryptography is used to ensure that none of the participants can +defraud the others without being detected immediately; however, in +practice a fradulent Exchange might go bankrupt instead of paying the +Merchants and thus the Exchange will need to be audited regularly like +any other banking institution. + +The system will be based on free software and open protocols. + +In this document, we describe the REST-based APIs between the various +components, internal architecture of key components, and how to get them +installed. + +------- +Preface +------- + +The *Operator Handbook* is for people who want to run a exchange or a merchant. +It focuses on how to install, configure and run the required software. + +.. toctree:: + :maxdepth: 2 + + global_licensing + versioning + +------------------------ +Web Integration Handbook +------------------------ + +The *Web Integration Handbook* is for those who want to interact with Taler +wallets on their own website. Integrators will also have to be familiar with +the material covered in the *Operator Handbook*. + + +.. toctree:: + :maxdepth: 2 + + integration-general + integration-bank + integration-merchant + +-------------------------------------- +Taler HTTP 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-bank + + wireformats diff --git a/api/integration-bank.rst b/api/integration-bank.rst new file mode 100644 index 00000000..1dc2ec8d --- /dev/null +++ b/api/integration-bank.rst @@ -0,0 +1,81 @@ +============================== +Interaction with bank websites +============================== + +This section describes how bank websites can interact with the +Taler wallet. + +Currently the following functionality is supported: + * Querying for the presence of a Taler wallet. + * Receiving change notifications from the Taler wallet. + * Creating a reserve. + + +For JavaScript code examples, see :ref:`communication`. + +------------------------- +Reserve Creation Request +------------------------- + +The bank website can request the creation of a :term:`reserve`. This operation +will require the user to specify the exchange where he wants to create the reserve +and the resolution of a CAPTCHA, before any action will be taken. + +As a result of the reserve creation request, the following steps will happen in sequence: + 1. The user chooses the desired amount from the bank's form + 2. Upon confirmation, the wallet fetches the desired amount from the user-filled form and + prompts the user for the *exchange base URL*. Then ask the user to confirm creating the + reserve. + 3. The wallet will create a key pair for the reserve. + 4. The wallet will request the CAPTCHA page to the bank. In that request's parameters it + communicates the desired amount, the reserve's public key and the exchange base URL to the + bank + 5. Upon successful resolution of the CAPTCHA by the user, the bank initiates the reserve + creation according to the gotten parameters. Together with `200 OK` status code sent back + to the wallet, it gets also a `ReserveCreated`_ object. + +Note that the reserve creation can be done by a SEPA wire transfer or some other means, +depending on the user's bank and chosen exchange. + +In response to the reserve creation request, the Taler wallet MAY cause the +current document location to be changed, in order to navigate to a +wallet-internal confirmation page. + +The bank requests reserve creation with the ``taler-create-reserve`` event. +The event data must be a `CreateReserveDetail`_: + + +.. _CreateReserveDetail: +.. code-block:: tsref + + interface CreateReserveDetail { + + // JSON 'amount' object. The amount the caller wants to transfer + // to the recipient's count + amount: Amount; + + // CAPTCHA's page URL which needs the following parameters + // query parameters: + // amount_value + // amount_fraction + // amount_currency + // reserve_pub + // exchange + // wire_details (URL encoding of /wire output from the exchange) + callback_url: string; + + // list of wire transfer types supported by the bank + // e.g. "SEPA", "TEST" + wt_types: Array + } + +.. _ReserveCreated: +.. code-block:: tsref + + interface ReserveCreated { + + // A URL informing the user about the succesfull outcome + // of his operation + redirect_url: string; + + } diff --git a/api/integration-general.rst b/api/integration-general.rst new file mode 100644 index 00000000..308ecf5a --- /dev/null +++ b/api/integration-general.rst @@ -0,0 +1,82 @@ +.. _integration-general: + +================================ +Taler Wallet Website Integration +================================ + +.. note:: + The wallet-Websites communication is switching to a new policy which + is NOT based on DOM events, therefore obsoleting this page. To be soon + documented. + + +Websites (such as banks and online shops) can communicate with +the Taler wallet by a standardized protocol. + +From a technical perspective, the Taller wallet communicates with +the website by sending and receiving `DOM events `_ +on the bank website's ``HTMLDocument``. + +DOM events used by Taler have the prefix ``taler-``. + +------------------------- +Wallet Presence Awareness +------------------------- + +The bank website queries the wallet's presence by sending a ``taler-probe`` event. The +event data should be `null`. + +If the wallet is present and active, it will respond with a ``taler-wallet-present`` event. + +While the user agent is displaying a website, the user might deactivate or +re-activate the wallet. A Taler-aware *should* react to those events, and +indicate to the user that they should (re-)enable the wallet if necessary. + +When the wallet is activated, the ``taler-wallet-load`` event is sent +by the wallet. When the wallet is deactivated, the ``taler-wallet-unload`` event +is sent by the wallet. + +.. _communication: + +---------------------- +Communication Example +---------------------- + +The bank website can send the event ``taler-XYZ`` with the event data ``eventData`` +to the wallet with the following JavaScript code: + +.. sourcecode:: javascript + + const myEvent = new CustomEvent("taler-XYZ", eventData); + document.dispatchEvent(myEvent); + +Events can be received by installing a listener: + + +.. sourcecode:: javascript + + function myListener(talerEvent) { + // handle event here! + } + document.addEventListener("taler-XYZ", myListener); + + +-------------------- +Normalized Base URLs +-------------------- + +Exchanges and merchants have a base URL for their service. This URL *must* be in a +canonical form when it is stored (e.g. in the wallet's database) or transmitted +(e.g. to a bank page). + +1. The URL must be absolute. This implies that the URL has a schema. +2. The path component of the URL must end with a slash. +3. The URL must not contain a fragment or query. + +When a user enters a URL that is, technically, relative (such as "alice.example.com/exchange"), wallets +*may* transform it into a canonical base URL ("http://alice.example.com/exchange/"). Other components *should not* accept +URLs that are not canonical. + +Rationale: Joining non-canonical URLs with relative URLs (e.g. "exchange.example.com" with "reserve/status") +results in different and slightly unexpected behavior in some URL handling libraries. +Canonical URLs give more predictable results with standard URL joining. diff --git a/api/integration-merchant.rst b/api/integration-merchant.rst new file mode 100644 index 00000000..f3221617 --- /dev/null +++ b/api/integration-merchant.rst @@ -0,0 +1,315 @@ +.. + This file is part of GNU TALER. + +.. + Note that this page is more a protocol-explaination than a guide that teaches + merchants how to work with Taler wallets + + Copyright (C) 2014, 2015, 2016 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 + @author Christian Grothoff + +================================== +Interaction with merchant websites +================================== + +.. _payprot: + ++++++++++++++++++++ +The payment process ++++++++++++++++++++ + +By design, the Taler payment process ensures the following properties: + +1. The user must see and accept a contract in a secure context before the payment happens. + That contract accounts for all the items which are supposed to be bought. + +2. The payment process must be idempotent, that is at any later time the customer must + be able to replay the payment and retrieve the resource he paid for. + In case where a physical item was bought, this online resource is the merchant's + order status page, which may contain tracking information for the customer. + Note that by `replaying the payment` we mean reusing the `same coins` used to pay for + the product the first time to get the `same product` the user got the first time. + So the replay does NOT subtract further credit from the user's total budget. + +3. Purchases are shareable: any purchase is given a URL that allows other users to + buy the same item(s). + +We call an *offer URL* any URL at the merchant's Web site that notifies the +wallet that the user needs to pay for something. The offer URL must take into +account that the user has no wallet installed, and manage the situation accordingly +(for example, by showing a credit card paywall). The notification can happen either +via JavaScript or via HTTP headers. + +The merchant needs to have a *contract URL* which generates the JSON +contract for Taler. Alternatively, the contract may be embedded +within the page returned by the offer URL and given to the wallet +via JavaScript or via an HTTP header. + +The merchant must also provide a *pay URL* to which the wallet can +transmit the payment. Again, how this URL is made known from the merchant +to the wallet, it is managed by the HTTP headers- or JavaScript-based protocol. + +The merchant must also have a *fulfillment URL*, that addresses points 2 and 3 above. +In particular, fulfillment URL is responsible for: + +* Deliver the final product to the user after the payment +* Instruct the wallet to send the payment to the pay URL +* Redirect the user to the offer URL in case they hit a shared fulfillment URL. + +Again, Taler provides two ways of doing that: JavaScript- and HTTP headers-based. + +Taler helps merchants on the JavaScript-based interaction by providing the +``taler-wallet-lib``. See https://git.taler.net/web-common.git/tree/taler-wallet-lib.ts + +------- +Example +------- + +For example, suppose Alice wants to pay for a movie. She will first +select the movie from the catalog, which directs her to the offer URL +*https://merchant/offer?x=8ru42*. This URL generates a "402 Payment +Required" response, and will instruct the wallet about the contract's +URL. Then the wallet downloads the contract that states that Alice is +about to buy a movie. The contract includes a fresh transaction ID, say 62. +Alice's browser detects the response code and displays the contract +for Alice. + +Alice then confirms that she wants to buy the movie. Her wallet +associates her confirmation with the details and a hash of the contract. +After Alice confirms, the wallet redirects her to the fulfillment URL, say +*https://merchant/fulfillment?x=8ru42&tid=62* that is specified in the +contract. + +The first time Alice visits this URL, the merchant will again +generate a "402 Payment Required" response, this time not including +the full contract but merely the hash of the contract (which includes +Alice's transaction ID 62), as well as the offer URL (which Alice +will ignore) and the pay URL. Alice's wallet will detect that +Alice already confirmed that she wants to execute this particular +contract. The wallet will then transmit the payment to the pay URL, +obtain a response from the merchant confirming that the payment was +successful, and then reload the fulfillment URL. + +This time (and every time in the future where Alice visits the +fulfillment URL), she receives the movie. If the browser has lost the +session state, the merchant will again ask her to pay (as it happened the +very first time she visited the fulfillment URL), and she will authenticate +by replaying the payment. + +If Alice decides to share the fulfillment URL with Bob and he visits +it, his browser will not have the right session state and furthermore +his wallet will not be able to replay the payment. Instead, his wallet +will automatically redirect Bob to the offer URL and allow him to +purchase the movie himself. + +.. _offer: + +--------------- +Making an offer +--------------- + +When a user visits a offer URL, the merchant returns a page that can interact +with the wallet either via JavaScript or by returning a "402 Payment Required". +This page's main objective is to inform the wallet on where it should get the +contract. In case of JavaScript interaction, the merchant should just return +a page whose javascript contains an invocation to ``offerContractFrom()`` +from ``taler-wallet-lib``. This function will download the contract from +`` and hand it to the wallet. + +In case of HTTP headers-based protocol, the merchant needs to set the header +`X-Taler-contract-url` to the contract URL. Once this information reaches the +browser, the wallet will takes action by reading that header and downloading +the contract. + +Either way, the contract gets to the wallet which then renders it to the user. + +.. _fulfillment: + +------------------------------- +Fulfillment interaction details +------------------------------- + +A payment process is triggered whenever the user visits a fulfillment +URL and he has no rights in the session state to get the items +accounted in the fulfillment URL. Note that after the user accepts a +contract, the wallet will automatically point the browser to the +fulfillment URL. + +Becasue fulfillment URLs implements replayable and shareable payments +(see points 2,3 above), fulfillment URL parameter must encompass all the +details necessary to reconstruct a contract. + +That saves the merchant from writing contracts to disk upon every contract +generation, and defer this operation until customers actually pay. + +.................. +HTTP headers based +.................. + +Once the fulfillment URL gets visited, deliver the final product if the user has +paid, otherwise: the merchant will reconstruct the contract and re-hash it, sending +back to the client a "402 Payment required" status code and some HTTP headers which +will help the wallet to manage the payment. Namely: + +* `X-taler-contract-hash` +* `X-taler-pay-URL` +* `X-taler-offer-URL` + +The wallet then looks at `X-taler-contract-hash`, and can face two situations: + +1. This hashcode is already present in the wallet's database (meaning that the user did accept the related contract), so the wallet can send the payment to `X-taler-pay-URL`. During this operation, the wallet associates the coins it sent to `X-taler-pay-URL` with this hashcode, so that it can replay payments whenever it gets this hashcode again. + +2. This hashcode is unknown to the wallet (meaning that the user visited a shared fulfillment URL). The wallet then points the browser to `X-taler-offer-URL`, which is in charge of generating a contract referring to the same items accounted in the fulfillment URL. Of course, the user is then able to accept or not the contract. + +................ +JavaScript based +................ + +Once the fulfillment URL gets visited, deliver the final product if the user has paid, otherwise: +the merchant will reconstruct the contract and re-hash it. Then it will return a page whose JavaScript +needs to include a call to ``taler.executeContract(..)``. See the following example: + +.. sourcecode:: html + + + + + + + .. + + + +The logic which will take place is the same as in the HTTP header based protocol. +Once ``executePayment(..)`` gets executed in the browser, it will hand its three +parameters to the wallet, which will: + +1. Send the payment to `` if `` is found in its database (meaning that the user accepted it). +2. Redirect the browser to ``, if `` is NOT found in its database, meaning that the user visited a shared fulfillment URL. + +-------------------- +Example: Essay Store +-------------------- + +This section is a high-level description of a merchant :ref:`frontend `, +and is inspired by our demonstration essay store running at `https://blog.demo.taler.net/`. +Basically, it tells how the frontend reacts to clients visiting `offer` and `fulfillment` +URLs. + +The website is implemented in Python+Flask, and is available at +https://git.taler.net/merchant-frontends.git/tree/talerfrontends/blog. + +The desired effect is that the homepage has a list of buyable articles, and once the +user clicks on one of them, they will either get the Taler :ref:`contract ` +or a credit card paywall if they have no Taler wallet installed. + +In particular, any buyable article on the homepage links to an `offer URL`: + +.. sourcecode:: html + + + ... +

How to write a frontend

+ ... + + +whence the offer URL design is as follows:: + + https:///essay/ + +`` is just a token that uniquely identifies the article within the shop. + +The server-side handler for the offer URL will return a special page to the client that +will either HTTP GET the contract from the frontend, or show the credit card paywall. +See `above `_ how this special page works. + +It is interesting to note that the fulfillment URL is just the offer URL plus +two additional parameters. It looks as follows:: + + https:///essay/?tid=×tamp= + +.. note:: + + Taler does not require that offer and fulfillment URL have this kind of relationship. + In fact, it is perfectly acceptable for the fulfillment URL to be hosted on a different + server under a different domain name. + +The fulfillment URL server-side handler implements the following logic: it checks the state +to see if `` has been payed, and if so, returns the article to the user. +If the user didn't pay, then it `executes` the contract by returning a special page to the +browser. The contract execution is the order to pay that the frontend gives to the wallet. + +Basically, the frontend points the wallet to the hashcode of the contract which is to be paid +and the wallet responds by giving coins to the frontend. Because the frontend doesn't perform +any cryptographic work by design, it forwards ``, `` and +`` to the frontend in order to get the contract's hashcode. + +See `above `_ for a detailed description of how the frontend triggers the +payment in the wallet. + +.................. +State and security +.................. + +The server-side state gets updated in two situations, (1) when an article is +"about" to be bought, which means when the user visits the fulfillment URL, +and (2) when the user actually pays. For (1), we use the contract hascode to +access the state, whereas in (2) we just define a list of payed articles. +For example: + +.. sourcecode:: python + + session[] = {'article_name': 'How_to_write_a_frontend'} # (1) + session['payed_articles'] = ['How_to_write_a_frontend', 'How_to_install_a_backend'] # (2) + +The list of payed articles is used by the frontend to deliver the article to the user: +if the article name is among ``session['payed_articles']``, then the user gets what they +paid for. + +The reason for using `` as the key is to prevent the wallet to send bogus +parameters along the fulfillment URL. `` is the contract hashcode that +the fulfillment handler gets from the backend using the fulfillment URL parameters. + +In fact, when the wallet sends the payment to the frontend pay handler, it has to provide +both coins and contract hashcode. That hascode is (1) verified by the backend when it +receives the coins, (2) used by the frontend to update the list of payed articles. + +See below an example of pay handler: + +.. sourcecode:: python + + ... + + # 'deposit_permission' is the JSON object sent by the wallet + # which contains coins and the contract hashcode. + response = send_payment_to_backend(deposit_permission) + + # The backend accepted the payment + if 200 == response.status_code: + # Here we pick the article name from the state defined at + # fulfillment time. + # deposit_permission['H_contract'] is the contract hashcode + payed_article = session[deposit_permission['H_contract']]['article_name'] + session['payed_articles'].append(payed_article) + + +So the wallet is forced to send a valid contract hashcode along the payment, +and since that hashcode is then used to update the list of payed articles, +the wallet is forced to send fulfillment URL parameters that match that hashcode, +therefore being valid parameters. diff --git a/api/wireformats.rst b/api/wireformats.rst new file mode 100644 index 00000000..4e154930 --- /dev/null +++ b/api/wireformats.rst @@ -0,0 +1,69 @@ +.. _wireformats: + +Wire Transfer Formats +===================== + +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 type of wire transfer +used. Since the wire transfers differ for each region, we document here the +ones currently supported by the exchange. + +TEST +---- + +The TEST 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 TEST +wire format in combination with the Taler's bank, it is thus possible to +fully test the Taler system without using "real" currencies. The wire +format for "TEST" is very simple, in that it only specifies an account +number in a field "account_number" and the URI of the bank: + + * `type`: the string constant `"test"` + * `bank_uri`: the URI of the bank (starting with `http://` or `https://`) + * `account_number`: the number of the account at the bank + +The account number given must be a positive 53-bit integer. +Additional fields may be present, but are not required. + +Note that a particular exchange is usually only supporting one +particular bank with the "TEST" wire format, so it is not possible for +a merchant with an account at a different bank to use "TEST" to +transfer funds across banks. After all, this is for testing and not +for real banking. + +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 *EURO*. 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 +contain a JSON object with the following fields: + + .. The following are taken from Page 33, SEPA_SCT.pdf . + + * `type`: the string constant `"sepa"` + * `iban`: the International Bank Account Number (IBAN) of the account of the beneficiary + * `name`: the name of the beneficiary + * `bic`: the Bank Identification Code (BIC) code of the beneficiary's bank + * `salt`: random salt (used to make brute-forcing the hash harder) + +The JSON object may optionally contain: + * `address`: the address of the Beneficiary + +The implementation of the SEPA plugin 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/conf.py b/conf.py deleted file mode 100644 index 8db3f93b..00000000 --- a/conf.py +++ /dev/null @@ -1,285 +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 Lesser 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 -""" -# -*- coding: utf-8 -*- -# -# neuro documentation build configuration file, created by -# sphinx-quickstart on Sat May 31 13:11:06 2014. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -needs_sphinx = '1.3' - -sys.path.append(os.path.abspath('exts')) - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'tsref', - 'sphinx.ext.todo', - 'sphinx.ext.pngmath', - 'sphinxcontrib.httpdomain' -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Taler' -copyright = u'2014, 2015, 2016 Florian Dold, Benedikt Muller, Sree Harsha Totakura, Christian Grothoff, Marcello Stanisci (GPLv3+ or GFDL 1.3+)' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '0.1' -# The full version, including alpha/beta/rc tags. -release = '0.1.0' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -html_show_sphinx = False - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'neurodoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'taler.tex', u'Taler Documentation', - u'F. Dold, B. Muller, S. H. Totakura, C. Grothoff', - 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'neuro', u'neuro Documentation', - [u'F. Dold, B. Muller, S. H. Totakura, C. Grothoff'], - 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'neuro', u'neuro Documentation', - u'F. Dold, B. Muller, S. H. Totakura, C. Grothoff', - 'neuro', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False diff --git a/configuration-basics.rst b/configuration-basics.rst deleted file mode 100644 index 50c3d532..00000000 --- a/configuration-basics.rst +++ /dev/null @@ -1,79 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014, 2015, 2016 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 - -====================== -Configuration in Taler -====================== - -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/`. - - --------------------- -Configuration format --------------------- - -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. diff --git a/deployment.rst b/deployment.rst deleted file mode 100644 index c0b07e43..00000000 --- a/deployment.rst +++ /dev/null @@ -1,231 +0,0 @@ -=================== -Deployment Protocol -=================== - ------- -Wallet ------- - -.. code-block:: none - - $ cd wallet-webex - - # check dependencies - $ ./configure - - # edit version and version_name - $ $EDITOR manifest.json - - $ make package-stable - -The built wallet is now ready in `taler-wallet-stable-${version_name}${version}.zip`. - -FIXME: here, we should do some semi-automated testing with selenium, to see -that everything works against `demo.taler.net`. - -The package can now be uploaded to https://chrome.google.com/webstore/developer/dashboard - -FIXME: include asset links and descriptions we use in the webstore in this document - -FIXME: include instructions for other app stores - - --------------------- -Deploying to stable --------------------- - -First, make sure that the deployment *AND* the deployment scripts work on the `test.taler.net` deployment. - -For all repositories that have a separate stable branch (currently exchange.git, -merchant.git, merchant-frontends.git, bank.git, landing.git) do: - -.. code-block:: none - - $ cd $REPO - $ git pull origin master stable - $ git checkout stable - - # option a: resolve conflicts resulting from hotfixes - $ git merge master - $ ... - - # option b: force stable to master - $ git update-ref refs/heads/stable master - - $ git push # possibly with --force - - # continue development - $ git checkout master - - -Log into taler.net with the account that is *not* active by looking -at the `sockets` symlink of the `demo` account. - -The following instructions wipe out the old deployment completely. - -.. code-block:: none - - $ ls -l ~demo/sockets - - [...] sockets -> /home/demo-green/sockets/ - -In this case, `demo-green` is the active deployment, and `demo-blue` should be updated. -After the update is over, the `/home/demo/sockets` symlink will be pointed to `demo-blue`. - -.. code-block:: none - - # Remove all existing files - $ find $HOME -exec rm -fr {} \; - - $ git clone /var/git/deployment.git - $ ./deployment/bootstrap-bluegreen demo - - # set environment appropriately - $ . activate - $ taler-deployment-build - - # upgrade the database! this - # process depends on the specific version - - $ taler-deployment-start - - # look at the logs, verify that everything is okay - -Now the symlink can be updated. - - - ------------------- -Database upgrades ------------------- - -The exchange db can be re-initialized with - -.. code-block:: none - - $ taler-exchange-dbinit -r - -CAUTION: YOU WILL LOSE ALL DATA WITH THIS! - - ---------------------- -Standalone deployment ---------------------- - -This tecnique aims to set a thorough Taler installation up on a -machine whose nginx configuration is configured by config files -from https://git.taler.net/deployment.git/tree/etc/nginx. - -This installation assumes that all the steps are run with ``$HOME`` -as ``$CWD``. - -The first step is to fetch the `deployment` repository, which hosts all -the needed scripts. - -.. code-block:: none - - # Adapt the repository's URI to your needs. - $ git clone /var/git/deployment.git/ - -The next step is to fetch all the codebases from all the components. - -.. code-block:: none - - $ ./deployment/bootstrap-standalone - -If the previous step succeeded, a file named ``activate`` should be now -in the ``$CWD``. It contains environmental definitions for ``$PATH`` and -database names. - -.. note:: - - Please *ignore* the output from the previous script when it succeeds, - which is - - .. code-block:: none - - WARNING: enabling "trust" authentication for local connections - You can change this by editing pg_hba.conf or using the option -A, or - --auth-local and --auth-host, the next time you run initdb. - - Success. You can now start the database server using: - - /usr/lib/postgresql/9.5/bin/pg_ctl -D talerdb -l logfile start - - The reason is that this message is generated by Postgresql's utilities and - you never need to start your database manually; it will be started by the - init script that launches all the Taler processes. - -Now we need to compile and install all the downloaded codebases. - -.. code-block:: none - - # We first update ``$PATH``, in order to make all the compilation - and configuration utilities available. - $ source activate - - # Double check if the previous step worked: $PATH should - # contain $HOME/local/bin. - $ echo $PATH - - # The actual compilation: - $ taler-deployment-build - -The following step will generate config files for all the components. -Please **note** that although a default currency will be picked up by the -script, it is possible to have a custom currency by setting the environment -variable ``TALER_CONFIG_CURRENCY`` to the wanted currency, and then runing -the config generator. - -.. code-block:: none - - $ taler-deployment-config-generate - -whereas the following one will place signatures inside wireformat JSON -files. - -.. code-block:: none - - $ taler-deployment-config-sign - -The next step is to generate `signkeys` and `denomkeys`. - -.. code-block:: none - - $ taler-deployment-keyup - -.. - An error of "invalid currency name" might be related to the current - policy of 12-chars limit for currency names; which is likely going to - be changed. - -It may be necessary to define database tables for the exchange. The -following command does that. - -.. code-block:: none - - # Erase all the data! - $ taler-exchange-dbinit -r - -As of the merchant backend, it creates tables at launch time, so it is -not required to define tables before launching it. `However`, if some -table's definition changed over the time, and there is a need to force -a redefinition of tables, then the following command accomplishes that -for the merchant: - -.. code-block:: none - - # Erase all the data! - $ taler-merchant-dbinit -r - -If all previous steps succeeded, it is now possible to launch all the -processes. That is accomplished by the following command: - -.. code-block:: none - - $ taler-deployment-start - -.. note:: - - Please make sure your nginx works correctly with its configuration - at ``/etc/nginx``. diff --git a/dev-exchange.rst b/dev-exchange.rst deleted file mode 100644 index 91278ee7..00000000 --- a/dev-exchange.rst +++ /dev/null @@ -1,144 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014, 2015, 2016 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 - -======== -Exchange -======== - -.. _keys-duration: - -------------- -Keys duration -------------- - -`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. - - - ---------------- -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 -------------------- - -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`: - -.. sourcecode:: c - - struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP { - struct TALER_ExchangePrivateKeyP signkey_priv; - struct TALER_ExchangeSigningKeyValidityPS issue; - }; - ------------------------- -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: - -.. sourcecode:: c - - 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()`. - -------------------------- -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: - -.. sourcecode:: c - - 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. diff --git a/dev-merchant.rst b/dev-merchant.rst deleted file mode 100644 index e4cd4cbc..00000000 --- a/dev-merchant.rst +++ /dev/null @@ -1,38 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014, 2015, 2016 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 - -======== -Merchant -======== - -.. _merchant-arch: - ------- -Design ------- - -In order for a merchant to be Taler-compatible, they need to run two distinct Web -services: a *frontend* and a *backend*. The former is typically the Web site where -the merchant exposes their goods, whereas the latter is a C program in charge of -making all the Taler-related cryptography. - -In details, the frontend gathers all the information from customers about sales, -and forwards it to the backend via its RESTful API. Typically, the backend will either -cryptographically process this data or just forward it to the exchange. - -That saves the frontend developers from dealing with cryptography in scripting -languages and from commmunicating at all with any exchange. - -Additionally, the backend RESTful API is such that a frontend might be run completely -database-less. diff --git a/dev-wallet-wx.rst b/dev-wallet-wx.rst deleted file mode 100644 index 8ba29975..00000000 --- a/dev-wallet-wx.rst +++ /dev/null @@ -1,212 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014, 2015, 2016 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 Florian Dold - -===================== -WebExtensions Wallet -===================== - ------------- -Introduction ------------- - -The WebExtensions Wallet (*wxwallet*) can be used to pay with GNU Taler on web -sites from within modern web browsers. The `WebExtensions -`_ API enables the development of -cross-browser extensions. Google Chrome / Chromium, Mozilla Firefox, Opera and -Microsoft Edge will all offer support for WebExtensions and thus be able to support Taler. - -Currently Chrome hast the best support for WebExtensions (since the API is a -superset of Chrome's extension API). - ------------------------ -Development Environment ------------------------ - -The *wxwallet* mainly written in the `TypeScript -`_ language, which is a statically typed -superset of JavaScript. - -While the *wxwallet* is mainly intended to be run from inside a browser, the -logic is implemented in browser-independent modules that can also be called -from other environments such as `nodejs `_. This is -especially useful for automatically running unit tests. - - ------------------ -Project Structure ------------------ - -.. parsed-literal:: - - **manifest.json** extension configuration - **package.json** node.js package configuration - **tsconfig.json** TypeScript compiler configuration - **gulpfile.js** Build tasks script - **lib/** - **vendor/** 3rd party libraries - **wallet/** actual application logic - **emscripten/** emscripten object file and glue - **test/** - **run_tests.js** nodejs entry point for tests - **tests/** test cases - **content_scripts/notify.ts** wallet<->website signaling - **backgrond/main.ts** backend entry point - **img/** static image resources - **style/** CSS stylesheets - **pages/** pages shown in browser tabs - **popup/** pages shown the extension popup - - -------------------- -Building the Wallet -------------------- - -To build the extension for use during development, simply run the TypeScript compiler -from the extension directory: - -.. code-block:: sh - - $ cd wallet.git/wallet_webextension/extension/ - $ tsc - -This will use the ``tsconfig.json`` with development options such as `source map`_ support. - -.. _`source map`: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit - -When TypeScript source files are added or deleted to the project, make sure that the -globs in ``gulpfile.js`` match them so that they will be compiled. The ``tsconfig.json`` -is generated by running: - - -.. code-block:: sh - - $ gulp tsconfig - -.. caution:: - - Do not edit the ``tsconfig.json`` manually. The source files should be defined in - one place, and that is ``gulpfile.js``. - -To pack the extension in a format that can be uploaded to the Google Webstore, run: - -.. code-block:: sh - - $ gulp package - -This will build the wallet without source maps, copy resource files (which also need to be -specified in ``gulpfile.js``) and create an archive. - - ----------- -Emscripten ----------- - -`Emscripten `_ is C/C++ -to JavaScript compiler. Emscripten is used in the *wxwallet* to access -low-level cryptography from *libgcrypt*, and miscellaneous functionality from -*libgnunetutil* and *libtalerwallet*. - -TODO: say things about wrappers - - --------------------------------------- -Target Environments and Modularization --------------------------------------- - -Modules in the wallet are declared in TypeScript with -the ES6 module syntax. These modules are then compiled -to `SystemJS `_ `register` modules. - -SystemJS modules can be loaded from the browser as well as from nodejs. -However they require special entry points that configure the module system, -load modules and execute code. Examples are `backgrond/main.ts` for the -browser and `test/run_tests.js` for nodejs. - -Note that special care has to be taken when loading the Emscript code, -as it is not compatible with the SystemJS module, even in the `globals` -compatibility mode. - -The TypeScript sources in the *wxwallet* are compiled down to ES5, both to -enable running in node.js without transpilers and to avoid a `bug -`_ in the TypeScript -compiler. - ----------------------------- -IndexedDB Query Abstractions ----------------------------- - -The *wxwallet* uses a fluent-style API for queries on IndexedDB. - -TODO: say more about this - - -------- -Testing -------- - -Test cases for the wallet are written in TypeScript and -run with `mochajs `_ and the `better-assert `_ assertion -library. - -Run the default test suite with ``npm run test``, which will -call `mocha` with the right parameters. - - --------------------- -Internationalisation --------------------- - -Strings in the JavaScript code are internationalised using the following functions: - -- *i18n*: translate string with arbitrary arguments, the result is returned as string. - -.. code-block:: js - - i18n`You have ${n} coins.` - -- *i18n.parts*: Interpolate i18nized values with arbitrary objects. - Useful for example to include HTML elements. - -.. code-block:: js - - i18n.parts`Visit ${link} to get more coins.` - -- *i18n.pluralize*: translate with plural form. - The i18n.number() function returns a ``PluralNumber`` object - that specifies the argument that determines the plural form, - if not present the first numeric argument is used. - -.. code-block:: js - - i18n.pluralize( - i18n`${i}: you have ${i18n.number(n)} coin.`, - `${i}: you have ${i18n.number(n)} coins.`); - -These functions are defined in ``lib/i18n.ts``. -Include ``lib/vendor/jed.js``, ``lib/i18n.js``, ``lib/i18n-strings.js`` to use them. - -To extract strings from sources and update the .po files, run: - -.. code-block:: sh - - $ make i18n - -In static HTML files the ``lang`` attribute is used for language-specific strings: - -.. code-block:: html - -

Hello World!

-

Hallo Welt!

- -``lib/i18n.js`` and ``style/lang.css`` needs to be included for this to work. diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..8db3f93b --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,285 @@ +""" + 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 Lesser 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 +""" +# -*- coding: utf-8 -*- +# +# neuro documentation build configuration file, created by +# sphinx-quickstart on Sat May 31 13:11:06 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = '1.3' + +sys.path.append(os.path.abspath('exts')) + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'tsref', + 'sphinx.ext.todo', + 'sphinx.ext.pngmath', + 'sphinxcontrib.httpdomain' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Taler' +copyright = u'2014, 2015, 2016 Florian Dold, Benedikt Muller, Sree Harsha Totakura, Christian Grothoff, Marcello Stanisci (GPLv3+ or GFDL 1.3+)' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.1' +# The full version, including alpha/beta/rc tags. +release = '0.1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'neurodoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'taler.tex', u'Taler Documentation', + u'F. Dold, B. Muller, S. H. Totakura, C. Grothoff', + 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'neuro', u'neuro Documentation', + [u'F. Dold, B. Muller, S. H. Totakura, C. Grothoff'], + 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'neuro', u'neuro Documentation', + u'F. Dold, B. Muller, S. H. Totakura, C. Grothoff', + 'neuro', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff --git a/docs/configuration-basics.rst b/docs/configuration-basics.rst new file mode 100644 index 00000000..50c3d532 --- /dev/null +++ b/docs/configuration-basics.rst @@ -0,0 +1,79 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016 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 + +====================== +Configuration in Taler +====================== + +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/`. + + +-------------------- +Configuration format +-------------------- + +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. diff --git a/docs/deployment.rst b/docs/deployment.rst new file mode 100644 index 00000000..c0b07e43 --- /dev/null +++ b/docs/deployment.rst @@ -0,0 +1,231 @@ +=================== +Deployment Protocol +=================== + +------ +Wallet +------ + +.. code-block:: none + + $ cd wallet-webex + + # check dependencies + $ ./configure + + # edit version and version_name + $ $EDITOR manifest.json + + $ make package-stable + +The built wallet is now ready in `taler-wallet-stable-${version_name}${version}.zip`. + +FIXME: here, we should do some semi-automated testing with selenium, to see +that everything works against `demo.taler.net`. + +The package can now be uploaded to https://chrome.google.com/webstore/developer/dashboard + +FIXME: include asset links and descriptions we use in the webstore in this document + +FIXME: include instructions for other app stores + + +-------------------- +Deploying to stable +-------------------- + +First, make sure that the deployment *AND* the deployment scripts work on the `test.taler.net` deployment. + +For all repositories that have a separate stable branch (currently exchange.git, +merchant.git, merchant-frontends.git, bank.git, landing.git) do: + +.. code-block:: none + + $ cd $REPO + $ git pull origin master stable + $ git checkout stable + + # option a: resolve conflicts resulting from hotfixes + $ git merge master + $ ... + + # option b: force stable to master + $ git update-ref refs/heads/stable master + + $ git push # possibly with --force + + # continue development + $ git checkout master + + +Log into taler.net with the account that is *not* active by looking +at the `sockets` symlink of the `demo` account. + +The following instructions wipe out the old deployment completely. + +.. code-block:: none + + $ ls -l ~demo/sockets + + [...] sockets -> /home/demo-green/sockets/ + +In this case, `demo-green` is the active deployment, and `demo-blue` should be updated. +After the update is over, the `/home/demo/sockets` symlink will be pointed to `demo-blue`. + +.. code-block:: none + + # Remove all existing files + $ find $HOME -exec rm -fr {} \; + + $ git clone /var/git/deployment.git + $ ./deployment/bootstrap-bluegreen demo + + # set environment appropriately + $ . activate + $ taler-deployment-build + + # upgrade the database! this + # process depends on the specific version + + $ taler-deployment-start + + # look at the logs, verify that everything is okay + +Now the symlink can be updated. + + + +------------------ +Database upgrades +------------------ + +The exchange db can be re-initialized with + +.. code-block:: none + + $ taler-exchange-dbinit -r + +CAUTION: YOU WILL LOSE ALL DATA WITH THIS! + + +--------------------- +Standalone deployment +--------------------- + +This tecnique aims to set a thorough Taler installation up on a +machine whose nginx configuration is configured by config files +from https://git.taler.net/deployment.git/tree/etc/nginx. + +This installation assumes that all the steps are run with ``$HOME`` +as ``$CWD``. + +The first step is to fetch the `deployment` repository, which hosts all +the needed scripts. + +.. code-block:: none + + # Adapt the repository's URI to your needs. + $ git clone /var/git/deployment.git/ + +The next step is to fetch all the codebases from all the components. + +.. code-block:: none + + $ ./deployment/bootstrap-standalone + +If the previous step succeeded, a file named ``activate`` should be now +in the ``$CWD``. It contains environmental definitions for ``$PATH`` and +database names. + +.. note:: + + Please *ignore* the output from the previous script when it succeeds, + which is + + .. code-block:: none + + WARNING: enabling "trust" authentication for local connections + You can change this by editing pg_hba.conf or using the option -A, or + --auth-local and --auth-host, the next time you run initdb. + + Success. You can now start the database server using: + + /usr/lib/postgresql/9.5/bin/pg_ctl -D talerdb -l logfile start + + The reason is that this message is generated by Postgresql's utilities and + you never need to start your database manually; it will be started by the + init script that launches all the Taler processes. + +Now we need to compile and install all the downloaded codebases. + +.. code-block:: none + + # We first update ``$PATH``, in order to make all the compilation + and configuration utilities available. + $ source activate + + # Double check if the previous step worked: $PATH should + # contain $HOME/local/bin. + $ echo $PATH + + # The actual compilation: + $ taler-deployment-build + +The following step will generate config files for all the components. +Please **note** that although a default currency will be picked up by the +script, it is possible to have a custom currency by setting the environment +variable ``TALER_CONFIG_CURRENCY`` to the wanted currency, and then runing +the config generator. + +.. code-block:: none + + $ taler-deployment-config-generate + +whereas the following one will place signatures inside wireformat JSON +files. + +.. code-block:: none + + $ taler-deployment-config-sign + +The next step is to generate `signkeys` and `denomkeys`. + +.. code-block:: none + + $ taler-deployment-keyup + +.. + An error of "invalid currency name" might be related to the current + policy of 12-chars limit for currency names; which is likely going to + be changed. + +It may be necessary to define database tables for the exchange. The +following command does that. + +.. code-block:: none + + # Erase all the data! + $ taler-exchange-dbinit -r + +As of the merchant backend, it creates tables at launch time, so it is +not required to define tables before launching it. `However`, if some +table's definition changed over the time, and there is a need to force +a redefinition of tables, then the following command accomplishes that +for the merchant: + +.. code-block:: none + + # Erase all the data! + $ taler-merchant-dbinit -r + +If all previous steps succeeded, it is now possible to launch all the +processes. That is accomplished by the following command: + +.. code-block:: none + + $ taler-deployment-start + +.. note:: + + Please make sure your nginx works correctly with its configuration + at ``/etc/nginx``. diff --git a/docs/dev-exchange.rst b/docs/dev-exchange.rst new file mode 100644 index 00000000..91278ee7 --- /dev/null +++ b/docs/dev-exchange.rst @@ -0,0 +1,144 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016 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 + +======== +Exchange +======== + +.. _keys-duration: + +------------- +Keys duration +------------- + +`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. + + + +--------------- +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 +------------------- + +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`: + +.. sourcecode:: c + + struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP { + struct TALER_ExchangePrivateKeyP signkey_priv; + struct TALER_ExchangeSigningKeyValidityPS issue; + }; + +------------------------ +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: + +.. sourcecode:: c + + 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()`. + +------------------------- +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: + +.. sourcecode:: c + + 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. diff --git a/docs/dev-merchant.rst b/docs/dev-merchant.rst new file mode 100644 index 00000000..e4cd4cbc --- /dev/null +++ b/docs/dev-merchant.rst @@ -0,0 +1,38 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016 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 + +======== +Merchant +======== + +.. _merchant-arch: + +------ +Design +------ + +In order for a merchant to be Taler-compatible, they need to run two distinct Web +services: a *frontend* and a *backend*. The former is typically the Web site where +the merchant exposes their goods, whereas the latter is a C program in charge of +making all the Taler-related cryptography. + +In details, the frontend gathers all the information from customers about sales, +and forwards it to the backend via its RESTful API. Typically, the backend will either +cryptographically process this data or just forward it to the exchange. + +That saves the frontend developers from dealing with cryptography in scripting +languages and from commmunicating at all with any exchange. + +Additionally, the backend RESTful API is such that a frontend might be run completely +database-less. diff --git a/docs/dev-wallet-wx.rst b/docs/dev-wallet-wx.rst new file mode 100644 index 00000000..8ba29975 --- /dev/null +++ b/docs/dev-wallet-wx.rst @@ -0,0 +1,212 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016 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 Florian Dold + +===================== +WebExtensions Wallet +===================== + +------------ +Introduction +------------ + +The WebExtensions Wallet (*wxwallet*) can be used to pay with GNU Taler on web +sites from within modern web browsers. The `WebExtensions +`_ API enables the development of +cross-browser extensions. Google Chrome / Chromium, Mozilla Firefox, Opera and +Microsoft Edge will all offer support for WebExtensions and thus be able to support Taler. + +Currently Chrome hast the best support for WebExtensions (since the API is a +superset of Chrome's extension API). + +----------------------- +Development Environment +----------------------- + +The *wxwallet* mainly written in the `TypeScript +`_ language, which is a statically typed +superset of JavaScript. + +While the *wxwallet* is mainly intended to be run from inside a browser, the +logic is implemented in browser-independent modules that can also be called +from other environments such as `nodejs `_. This is +especially useful for automatically running unit tests. + + +----------------- +Project Structure +----------------- + +.. parsed-literal:: + + **manifest.json** extension configuration + **package.json** node.js package configuration + **tsconfig.json** TypeScript compiler configuration + **gulpfile.js** Build tasks script + **lib/** + **vendor/** 3rd party libraries + **wallet/** actual application logic + **emscripten/** emscripten object file and glue + **test/** + **run_tests.js** nodejs entry point for tests + **tests/** test cases + **content_scripts/notify.ts** wallet<->website signaling + **backgrond/main.ts** backend entry point + **img/** static image resources + **style/** CSS stylesheets + **pages/** pages shown in browser tabs + **popup/** pages shown the extension popup + + +------------------- +Building the Wallet +------------------- + +To build the extension for use during development, simply run the TypeScript compiler +from the extension directory: + +.. code-block:: sh + + $ cd wallet.git/wallet_webextension/extension/ + $ tsc + +This will use the ``tsconfig.json`` with development options such as `source map`_ support. + +.. _`source map`: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit + +When TypeScript source files are added or deleted to the project, make sure that the +globs in ``gulpfile.js`` match them so that they will be compiled. The ``tsconfig.json`` +is generated by running: + + +.. code-block:: sh + + $ gulp tsconfig + +.. caution:: + + Do not edit the ``tsconfig.json`` manually. The source files should be defined in + one place, and that is ``gulpfile.js``. + +To pack the extension in a format that can be uploaded to the Google Webstore, run: + +.. code-block:: sh + + $ gulp package + +This will build the wallet without source maps, copy resource files (which also need to be +specified in ``gulpfile.js``) and create an archive. + + +---------- +Emscripten +---------- + +`Emscripten `_ is C/C++ +to JavaScript compiler. Emscripten is used in the *wxwallet* to access +low-level cryptography from *libgcrypt*, and miscellaneous functionality from +*libgnunetutil* and *libtalerwallet*. + +TODO: say things about wrappers + + +-------------------------------------- +Target Environments and Modularization +-------------------------------------- + +Modules in the wallet are declared in TypeScript with +the ES6 module syntax. These modules are then compiled +to `SystemJS `_ `register` modules. + +SystemJS modules can be loaded from the browser as well as from nodejs. +However they require special entry points that configure the module system, +load modules and execute code. Examples are `backgrond/main.ts` for the +browser and `test/run_tests.js` for nodejs. + +Note that special care has to be taken when loading the Emscript code, +as it is not compatible with the SystemJS module, even in the `globals` +compatibility mode. + +The TypeScript sources in the *wxwallet* are compiled down to ES5, both to +enable running in node.js without transpilers and to avoid a `bug +`_ in the TypeScript +compiler. + +---------------------------- +IndexedDB Query Abstractions +---------------------------- + +The *wxwallet* uses a fluent-style API for queries on IndexedDB. + +TODO: say more about this + + +------- +Testing +------- + +Test cases for the wallet are written in TypeScript and +run with `mochajs `_ and the `better-assert `_ assertion +library. + +Run the default test suite with ``npm run test``, which will +call `mocha` with the right parameters. + + +-------------------- +Internationalisation +-------------------- + +Strings in the JavaScript code are internationalised using the following functions: + +- *i18n*: translate string with arbitrary arguments, the result is returned as string. + +.. code-block:: js + + i18n`You have ${n} coins.` + +- *i18n.parts*: Interpolate i18nized values with arbitrary objects. + Useful for example to include HTML elements. + +.. code-block:: js + + i18n.parts`Visit ${link} to get more coins.` + +- *i18n.pluralize*: translate with plural form. + The i18n.number() function returns a ``PluralNumber`` object + that specifies the argument that determines the plural form, + if not present the first numeric argument is used. + +.. code-block:: js + + i18n.pluralize( + i18n`${i}: you have ${i18n.number(n)} coin.`, + `${i}: you have ${i18n.number(n)} coins.`); + +These functions are defined in ``lib/i18n.ts``. +Include ``lib/vendor/jed.js``, ``lib/i18n.js``, ``lib/i18n-strings.js`` to use them. + +To extract strings from sources and update the .po files, run: + +.. code-block:: sh + + $ make i18n + +In static HTML files the ``lang`` attribute is used for language-specific strings: + +.. code-block:: html + +

Hello World!

+

Hallo Welt!

+ +``lib/i18n.js`` and ``style/lang.css`` needs to be included for this to work. diff --git a/docs/example-essay-store.rst b/docs/example-essay-store.rst new file mode 100644 index 00000000..19428019 --- /dev/null +++ b/docs/example-essay-store.rst @@ -0,0 +1,615 @@ +.. + This file is part of GNU TALER. + + Copyright (C) 2014, 2015, 2016 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 + +==================== +Example: Essay Store +==================== + +This section shows how to set up a merchant :ref:`frontend `, and is +inspired by our demonstration shop running at `https://shop.demo.taler.net/`. +It is recommended that the reader is already familiar with the +:ref:`payment protocol and terminology `. + +The code we are going to describe is available at +https://git.taler.net/merchant-frontends.git/tree/talerfrontends/blog +and is implemented in Python+Flask. + +The frontend shows a list of buyable articles in its homepage, and once the +user clicks one of them, they will either get the Taler :ref:`contract ` +or a credit card paywall if they don't have the Taler wallet. + +Each article thus links to a `offer URL`, whose layout is shown below. + + `https://shop.demo.taler.net/essay/Appendix_A:_A_Note_on_Software` + +Once the server side logic receives a request for a offer URL, it needs to +instruct the wallet to retrieve a Taler contract. This action can be taken +either with or **without** the use of JavaScript, see the next section. + +----------------------- +Triggering the contract +----------------------- + +It is important to note that the contract is not returned simply +as the offer URL's response, but rather the frontend `instructs` +the browser on how to retrieve the contract. That is needed for +the right handling of the cases where the wallet is not installed. + +.. note:: + + The code samples shown below are intentionally "incomplete", as often + one function contains logic for multiple actions. Thus in order to not + mix concepts form different actions under one section, parts of code not + related to the section being documented have been left out. + +**With JavaScript** + +In this case, the objective is to call the function ``taler.offerContractFrom()`` into the user browser, which will then retrieve the +contract. In order to do that, we return a HTML page, whose +template is in ``talerfrontends/blog/templates/purchase.html``, +that imports ``taler-wallet-lib.js``, so that the function +``taler.offerContractFrom()`` can be invoked into the user's +browser. + +The server side handler for a offer URL needs to render ``purchase.html`` by passing +the right parameters to ``taler.offerContractFrom()``. + +The rendering is done by the ``article`` function at ``talerfrontends/blog/blog.py``, +and is done by Flask's ``render_template()``, see below. + +.. sourcecode:: python + + # 'name' is the article name, and is set to the right value + # by Flask + # The 'data' parameter is used to send images along + # the articles, however its use is beyond the scope of + # this survey. + def article(name, data=None): + ... + ... + + return render_template('templates/purchase.html', + article_name=name, + no_contract=1, + contract_url=quote(contract_url), + data_attribute="data-taler-contractoffer=%s" % contract_url) + +After the rendering, (part of) ``purchase.html`` will look like shown below. + +.. sourcecode:: html + + ... + + + ... + + + ... + ... + +
+

+ Oops, it looks like you don't have a Taler wallet installed. Why don't you enter + all your credit card details before reading the article? You can also + use GNU Taler to complete the purchase at any time. +

+ +
+ First name

+ Family name

+ Age

+ Nationality

+ Gender
Male + CC number

+ Female
+
+
+ +
+
+ +
+ Processing payment with GNU Taler, please wait +
+ ... + +The script ``purchase.js`` is now in charge of implementing the behaviour we seek. +It needs to register two handlers: one called whenever the wallet is detected in the +browser, the other if the user has no wallet installed. + +That is done with: + +.. sourcecode:: javascript + + taler.onPresent(handleWalletPresent); + taler.onAbsent(handleWalletAbsent); + +Note that the ``taler`` object is exported by ``taler-wallet-lib.js``, and contains all +is needed to communicate with the wallet. + + +``handleWalletAbsent`` doesn't need to do much: it has to only hide the "please wait" +message and uncover the credit card pay form. See below. + +.. sourcecode:: javascript + + function handleWalletAbsent() { + // Hide "please wait" message + document.getElementById("talerwait").style.display = "none"; + // Uncover credit card pay form + document.body.style.display = ""; + } + +On the other hand, ``handleWalletPresent`` needs to firstly hide the credit card +pay form and show the "please wait" message. After that, it needs to fetch the +contract URL from the responsible ``meta`` tag, and finally invoke ``taler.offerContractFrom()`` using it. See below both parts. + +.. sourcecode:: javascript + + function handleWalletPresent() { + // Hide credit card paywall + document.getElementById("ccfakeform").style.display = "none"; + // Show "please wait" message + document.getElementById("talerwait").style.display = ""; + ... + ... + // Fetch contract URL from 'meta' tag. + let contract_url = document.querySelectorAll("[name=contract_url]")[0]; + // If this call is successful, it will obtain the contract, + // hand it to the wallet, so the wallet can eventually + // show it to the user. + taler.offerContractFrom(decodeURIComponent(contract_url.getAttribute("value"))); + ... + } + +.. note:: + + In order to get our code validated by W3C validators, we can't have inline + JavaScript in our pages, we are forced to import any used script instead. + +**Without JavaScript** + +This case is handled by the function ``article`` defined in +``talerfrontends/blog/blog.py``. Its objective is to set the "402 Payment +Required" HTTP status code, and the HTTP header ``X-Taler-Contract-Url`` +to the actual contract's URL for this purchase. + +Upon returning such a response, the wallet will automatically fetch the +contract from the URL indicated by ``X-Taler-Contract-Url``, and show it +to the user. + +Below is shown how the function ``article`` prepares and returns such a +response. + +.. sourcecode:: python + + # 'name' is the article name, and is set to the right value + # by Flask + # The 'data' parameter is used to send images along + # the articles, however its use is beyond the scope of + # this survey. + def article(name, data=None): + ... + ... + + # Create response. + response = make_response(render_template('templates/fallback.html'), 402) + # Set "X-Taler-Contract-Url" header to the contract's URL. + response.headers["X-Taler-Contract-Url"] = contract_url + return response + +The ``make_response`` function is exported by Flask, so it's beyond the scope +of this document to explain it; however, it returns a "response object" having +the "402 Payment Required" as HTTP status code, and the +HTML file ``talerfrontends/blog/templates/fallback.html`` as the body. +``fallback.html`` contains the credit card pay form, so that if the wallet is +not installed, the browser would keep that page shown. + +``contract_url`` is defined in the earlier steps of the same function; however, +in this example it looks like: + + `https://shop.demo.taler.net/essay/generate-contract?article_name=Appendix_A:_A_Note_on_Software`. + +The frontend will also have to provide the contract. That is done +by the handler ``generate_contract``, defined in +``talerfrontends/blog/blog.py``. See below. + +.. sourcecode:: python + + def generate_contract(): + now = int(time.time()) + tid = random.randint(1, 2**50) + article_name = expect_parameter("article_name") + contract = make_contract(article_name=article_name, tid=tid, timestamp=now) + contract_resp = sign_contract(contract) + logger.info("generated contract: %s" % str(contract_resp)) + return jsonify(**contract_resp) + + +Its task is to feed the ``make_contract`` subroutine with all the +values it needs to generate a contract. Those values are: the timestamp +for the contract, the transaction ID, and the article name; respectively, +``now``, ``tid``, and ``article_name``. + +After ``make_contract`` returns, the variable ``contract`` will hold a +`dict` type that complies with a contract :ref:`proposition `. +We then call ``sign_contract`` feeding it with the proposition, so that +it can forward it to the backend and return it signed. Finally we return +the signed proposition, complying with the :ref:`Offer ` object. + +For simplicity, any article costs the same price, so the frontend +doesn't need to map articles to prices. + +Both ``make_contract`` and ``sign_contract`` are defined in +``talerfrontends/blog/helpers.py``. + +At this point, the user can accept the contract, which triggers the wallet +to visit the fulfillment page. The main logic for a fulfillment page handler +is to (1) return the claimed product, if it has been paid, or (2) instruct the +wallet to send the payment. + +----------------- +Fulfillment logic +----------------- + +The state accounts for a product being paid or not, so the fulfillment handler +will firstly check that: + +.. sourcecode:: python + + # 'name' is the article name, and is set to the right value + # by Flask + # The 'data' parameter is used to send images along + # the articles, however its use is beyond the scope of + # this survey. + def article(name, data=None): + # Get list of payed articles from the state + payed_articles = session.get("payed_articles", []) + + if name in payed_articles: + ... + # The articles has been paid, so return it to the + # customer. + return send_file(get_article_file(article)) + ... + +In case the article has not been paid yet, the fulfillment handler needs +to `reconstruct` the contract, in order to get a precise reference about the +purchase in being served. + +All the information needed to reconstruct the contract is contained in the +fulfillment URL parameters. See below the URL layout: + + `https://shop.demo.taler.net/essay/Appendix_A:_A_Note_on_Software?uuid=×tamp=tid=` + +The way the contract is reconstructed is exactly the same as it was generated +in the previous steps: we need to call ``make_contract`` to get the original +:ref:`proposition ` and then ``sign_contract``. Recall that aside +from allowing the backend to add missing fields to the proposition, ``sign_contract`` +returns the contract hashcode also, that we should compare with the ``uuid`` +parameter provided by the wallet. + +In our blog, all the fulfillment logic is implemented in the function ``article``, +defined in ``talerfrontends/blog/blog.py``. It is important to note that this +function is `the same` function that runs the offer URL; in fact, as long as your +URL design allows it, it is not mandatory to split up things. In our example, the +offer URL differs from the fulfillment URL respect to the number (and type) of +parameters, so the ``article`` function can easily decide whether it has to handle +a "offer" or a "fulfillment" case. See below how the function detects the right +case and reconstructs the contract. + +.. sourcecode:: python + + # 'name' is the article name, and is set to the right value + # by Flask + # The 'data' parameter is used to send images along + # the articles, however its use is beyond the scope of + # this survey. + def article(name, data=None): + + ... + hc = request.args.get("uuid") + tid_str = request.args.get("tid") + timestamp_str = request.args.get("timestamp") + if hc is None or tid_str is None or timestamp_str is None: + # Offer URL case. + contract_url = make_url("/generate-contract", ("article_name",name)) + ... # Go on operating the offer URL and return + + # Fulfillment URL case from here on. + try: + tid = int(tid_str) + except ValueError: + raise MalformedParameterError("tid") + try: + timestamp = int(timestamp_str) + except ValueError: + raise MalformedParameterError("timestamp") + + restored_contract = make_contract(article_name=name, tid=tid, timestamp=timestamp) + contract_resp = sign_contract(restored_contract) + + # Return error if uuid mismatch with the hashcode coming from the backend + if contract_resp["H_contract"] != hc: + e = jsonify(error="contract mismatch", was=hc, expected=contract_resp["H_contract"]) + return e, 400 + + # We save the article's name in the state since after + # receiving the payment this value will point to the + # article to be delivered to the customer. Note how the + # contract's hashcode is used to index the state. + session[hc] = si = session.get(hc, {}) + si['article_name'] = name + + +After a successful contract reconstruction, the handler needs to instruct +the wallet to actually send the payment. There are as usual two ways this +can be accomplished: with and without JavaScript. + +**With JavaScript** + +.. + Mention that the template is the same we used for a offer URL! + +We return a HTML page, whose template is in +``talerfrontends/blog/templates/purchase.html``, that imports ``taler-wallet-lib.js``, +so that the function ``taler.executePayment()`` can be invoked into the user's +browser. + +The fulfillment handler needs to render ``purchase.html`` so that the right +parameters get passed to ``taler.executePayment()``. + +See below how the function ``article`` does the rendering. + +.. sourcecode:: python + + # 'name' is the article name, and is set to the right value + # by Flask + # The 'data' parameter is used to send images along + # the articles, however its use is beyond the scope of + # this survey. + def article(name, data=None): + + ... + ... + + return render_template('templates/purchase.html', + hc=hc, + pay_url=quote(pay_url), + offering_url=quote(offering_url), + article_name=name, + no_contract=0, + data_attribute="data-taler-executecontract=%s,%s,%s" % (hc, pay_url, offering_url)) + +After the rendering, (part of) ``purchase.html`` will look like shown below. + +.. sourcecode:: html + + ... + + + ... + + + + + + ... + ... + +
+

+ Oops, it looks like you don't have a Taler wallet installed. Why don't you enter + all your credit card details before reading the article? You can also + use GNU Taler to complete the purchase at any time. +

+ +
+ +
+
+ +
+ Processing payment with GNU Taler, please wait +
+ ... + +The script ``purchase.js`` is now in charge of calling ``taler.executePayment()``. +It will try to register two handlers: one called whenever the wallet is detected in the +browser, the other if the user has no wallet installed. + +That is done with: + +.. sourcecode:: javascript + + taler.onPresent(handleWalletPresent); + taler.onAbsent(handleWalletAbsent); + +.. note:: + + So far, the template and the imported script (``purchase.js``) + are exactly the same as the offer URL case, since we use them + for both cases. See below how the script distinguishes "offer" + from "fulfillment" case. + +Note that the ``taler`` object is exported by ``taler-wallet-lib.js``, and contains all +is needed to communicate with the wallet. + + +``handleWalletAbsent`` doesn't need to do much: it has to only hide the "please wait" +message and uncover the credit card pay form. See below. + +.. sourcecode:: javascript + + function handleWalletAbsent() { + // Hide "please wait" message + document.getElementById("talerwait").style.display = "none"; + // Uncover credit card pay form + document.body.style.display = ""; + } + +On the other hand, ``handleWalletPresent`` needs to firstly hide the credit card +pay form and show the "please wait" message. After that, it needs to fetch the +needed parameters from the responsible ``meta`` tags, and finally invoke +``taler.offerContractFrom()`` using those parameters. See below its whole definition. +Note, that since we are in the fulfillment case, the credit card pay form is `almost` +useless, as it is highly unlikely that the wallet is not installed. + +.. sourcecode:: javascript + + function handleWalletPresent() { + // Hide the credit card pay form + document.getElementById("ccfakeform").style.display = "none"; + // Show "please wait" message + document.getElementById("talerwait").style.display = ""; + + // The `no_contract` value is provided by the function `article` via a + // 'meta' tag in the template. When this value equals 1, then we are in the + // "offer" URL case, otherwise we are in the "fulfillment" URL case. + let no_contract = document.querySelectorAll("[name=no_contract]")[0]; + if (Number(no_contract.getAttribute("value"))) { + // "Offer" case + let contract_url = document.querySelectorAll("[name=contract_url]")[0]; + taler.offerContractFrom(decodeURIComponent(contract_url.getAttribute("value"))); + } + else { + // "Fulfillment" case. + let hc = document.querySelectorAll("[name=hc]")[0]; + let pay_url = document.querySelectorAll("[name=pay_url]")[0]; + let offering_url = document.querySelectorAll("[name=offering_url]")[0]; + taler.executePayment(hc.getAttribute("value"), + decodeURIComponent(pay_url.getAttribute("value")), + decodeURIComponent(offering_url.getAttribute("value"))); + } + } + +Once the browser executes ``taler.executePayment(...)``, the wallet will send the coins +to ``pay_url``. Once the payment succeeds, the wallet will again visit the +fulfillment URL, this time getting the article thanks to the "payed" status set by +the ``pay_url`` handler. + +**Without JavaScript** + +This case is handled by the function ``article`` defined in +``talerfrontends/blog/blog.py``. Its objective is to set the "402 Payment +Required" HTTP status code, along with the HTTP headers ``X-Taler-Contract-Hash``, +``X-Taler-Pay-Url``, and ``X-Taler-Offer-Url``. + +.. + FIXME: + Are those three parameters anywhere, at least 'kindof' introduced? + +Upon returning such a response, the wallet will automatically send the +payment to the URL indicated in ``X-Taler-Pay-Url``. + +The excerpt below shows how the function ``article`` prepares and returns such a +response. + +.. sourcecode:: python + + # 'name' is the article name, and is set to the right value + # by Flask + # The 'data' parameter is used to send images along + # the articles, however its use is beyond the scope of + # this survey. + def article(name, data=None): + ... + + # 'make_response' is exported by Flask. It returns a + # "response object" with customizable status code, HTTP + # headers and body + response = make_response(render_template('templates/fallback.html'), 402) + response.headers["X-Taler-Contract-Hash"] = hc + response.headers["X-Taler-Pay-Url"] = pay_url + response.headers["X-Taler-Offer-Url"] = offering_url + return response + +The template ``fallback.html`` contains the credit card pay form, which will be +used in the rare case where the wallet would not be detected in a fulfillment +session. Once the payment succeeds, the wallet will again visits the +fulfillment URL, this time getting the article thanks to the "payed" status set by +the ``pay_url`` handler. + +--------- +Pay logic +--------- + +The pay handler for the blog is implemented by the function +``pay`` at ``talerfrontends/blog/blog.py``. Its main duty is +to receive the :ref:`deposit permission ` +from the wallet, forward it to the backend, and return the outcome +to the wallet. See below the main steps of its implementation. + +.. sourcecode:: python + + def pay(): + # Get the uploaded deposit permission + deposit_permission = request.get_json() + + if deposit_permission is None: + e = jsonify(error="no json in body") + return e, 400 + + # Pick the contract's hashcode from deposit permission + hc = deposit_permission.get("H_contract") + + # Return error if no hashcode was found + if hc is None: + e = jsonify(error="malformed deposit permission", hint="H_contract missing") + return e, 400 + + # Get a handle to the state for this contract, using the + # hashcode from deposit permission as the index + si = session.get(hc) + + # If no session was found for this contract, then either it + # expired or one of the hashcodes (the one we got from + # reconstructing the contract in the fulfillment handler, + # and the one we just picked from the deposit permission) + # is bogus. Note how using the contract's hashcode as index + # makes harder for the wallet to use different hashcodes + # in different steps of the protocol. + if si is None: + e = jsonify(error="no session for contract") + return e, 400 + + # Forward the deposit permission to the backend + r = requests.post(urljoin(BACKEND_URL, 'pay'), json=deposit_permission) + + # Return error if the backend returned a HTTP status code + # other than 200 OK + if 200 != r.status_code: + raise BackendError(r.status_code, r.text) + + # The payment went through.. + ... + + # Resume the article name + article = si["article_name"] + + # Set the article's state as "payed". This is realized by + # appending it to a *list* of articles the customer is currently + # allowed to read. + payed_articles = session["payed_articles"] = session.get("payed_articles", []) + if article not in payed_articles: + payed_articles.append(article) + + ... + + # Return success + return r.text, 200 diff --git a/docs/exts/__pycache__/tsref.cpython-35.pyc b/docs/exts/__pycache__/tsref.cpython-35.pyc new file mode 100644 index 00000000..abc92f00 Binary files /dev/null and b/docs/exts/__pycache__/tsref.cpython-35.pyc differ diff --git a/docs/exts/tsref.py b/docs/exts/tsref.py new file mode 100644 index 00000000..8187f67f --- /dev/null +++ b/docs/exts/tsref.py @@ -0,0 +1,233 @@ +""" + This file is part of GNU TALER. + Copyright (C) 2014, 2015 GNUnet e.V. and INRIA + TALER 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, 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 +""" + +""" +This extension adds a new lexer "tsref" for TypeScript, which +allows reST-style links inside comments (`LinkName`_), +and semi-automatically adds links to the definition of types. + +For type TYPE, a reference to tsref-type-TYPE is added. + +Known bugs and limitations: + - The way the extension works right now interferes wiht + Sphinx's caching, the build directory should be cleared + before every build. +""" + + +from pygments.util import get_bool_opt +from pygments.token import Name, Comment, Token, _TokenType +from pygments.filter import Filter +from sphinx.highlighting import PygmentsBridge +from sphinx.builders.html import StandaloneHTMLBuilder +from sphinx.pygments_styles import SphinxStyle +from pygments.formatters import HtmlFormatter +from docutils import nodes +from docutils.nodes import make_id +import re + + +_escape_html_table = { + ord('&'): u'&', + ord('<'): u'<', + ord('>'): u'>', + ord('"'): u'"', + ord("'"): u''', +} + + +class LinkingHtmlFormatter(HtmlFormatter): + def __init__(self, **kwargs): + super(LinkingHtmlFormatter, self).__init__(**kwargs) + self._builder = kwargs['_builder'] + + def _fmt(self, value, tok): + cls = self._get_css_class(tok) + href = tok_getprop(tok, "href") + caption = tok_getprop(tok, "caption") + content = caption if caption is not None else value + if href: + value = '%s' % (href, content) + if cls is None or cls == "": + return value + return '%s' % (cls, value) + + def _format_lines(self, tokensource): + """ + Just format the tokens, without any wrapping tags. + Yield individual lines. + """ + lsep = self.lineseparator + escape_table = _escape_html_table + + line = '' + for ttype, value in tokensource: + link = get_annotation(ttype, "link") + + parts = value.translate(escape_table).split('\n') + + if len(parts) == 0: + # empty token, usually should not happen + pass + elif len(parts) == 1: + # no newline before or after token + line += self._fmt(parts[0], ttype) + else: + line += self._fmt(parts[0], ttype) + yield 1, line + lsep + for part in parts[1:-1]: + yield 1, self._fmt(part, ttype) + lsep + line = self._fmt(parts[-1], ttype) + + if line: + yield 1, line + lsep + + +class MyPygmentsBridge(PygmentsBridge): + def __init__(self, builder, trim_doctest_flags): + self.dest = "html" + self.trim_doctest_flags = trim_doctest_flags + self.formatter_args = {'style': SphinxStyle, '_builder': builder} + self.formatter = LinkingHtmlFormatter + + +class MyHtmlBuilder(StandaloneHTMLBuilder): + name = "html-linked" + def init_highlighter(self): + if self.config.pygments_style is not None: + style = self.config.pygments_style + elif self.theme: + style = self.theme.get_confstr('theme', 'pygments_style', 'none') + else: + style = 'sphinx' + self.highlighter = MyPygmentsBridge(self, self.config.trim_doctest_flags) + + def write_doc(self, docname, doctree): + self._current_docname = docname + super(MyHtmlBuilder, self).write_doc(docname, doctree) + + +def get_annotation(tok, key): + if not hasattr(tok, "kv"): + return None + return tok.kv.get(key) + + +def copy_token(tok): + new_tok = _TokenType(tok) + # This part is very fragile against API changes ... + new_tok.subtypes = set(tok.subtypes) + new_tok.parent = tok.parent + return new_tok + + +def tok_setprop(tok, key, value): + tokid = id(tok) + e = token_props.get(tokid) + if e is None: + e = token_props[tokid] = (tok, {}) + _, kv = e + kv[key] = value + + +def tok_getprop(tok, key): + tokid = id(tok) + e = token_props.get(tokid) + if e is None: + return None + _, kv = e + return kv.get(key) + + +link_reg = re.compile(r"`([^`<]+)\s*(?:<([^>]+)>)?\s*`_") + +# Map from token id to props. +# Properties can't be added to tokens +# since they derive from Python's tuple. +token_props = {} + + +class LinkFilter(Filter): + def __init__(self, app, **options): + self.app = app + Filter.__init__(self, **options) + + def filter(self, lexer, stream): + id_to_doc = self.app.env.domaindata.get("_tsref", {}) + for ttype, value in stream: + if ttype in Token.Keyword.Type: + defname = make_id('tsref-type-' + value); + t = copy_token(ttype) + if defname in id_to_doc: + docname = id_to_doc[defname] + href = self.app.builder.get_target_uri(docname) + "#" + defname + tok_setprop(t, "href", href) + + yield t, value + elif ttype in Token.Comment: + last = 0 + for m in re.finditer(link_reg, value): + pre = value[last:m.start()] + if pre: + yield ttype, pre + t = copy_token(ttype) + x1, x2 = m.groups() + if x2 is None: + caption = x1.strip() + id = make_id(x1) + else: + caption = x1.strip() + id = make_id(x2) + if id in id_to_doc: + docname = id_to_doc[id] + href = self.app.builder.get_target_uri(docname) + "#" + id + tok_setprop(t, "href", href) + tok_setprop(t, "caption", caption) + else: + self.app.builder.warn("unresolved link target in comment: " + id) + yield t, m.group(1) + last = m.end() + post = value[last:] + if post: + yield ttype, post + else: + yield ttype, value + + + +def remember_targets(app, doctree): + docname = app.env.docname + id_to_doc = app.env.domaindata.get("_tsref", None) + if id_to_doc is None: + id_to_doc = app.env.domaindata["_tsref"] = {} + for node in doctree.traverse(): + if not isinstance(node, nodes.Element): + continue + ids = node.get("ids") + if ids: + for id in ids: + id_to_doc[id] = docname + + +def setup(app): + from sphinx.highlighting import lexers + from pygments.lexers import TypeScriptLexer + from pygments.token import Name + from pygments.filters import NameHighlightFilter + lexer = TypeScriptLexer() + lexer.add_filter(LinkFilter(app)) + app.add_lexer('tsref', lexer) + app.add_builder(MyHtmlBuilder) + app.connect("doctree-read", remember_targets) diff --git a/docs/global_licensing.rst b/docs/global_licensing.rst new file mode 100644 index 00000000..7a5e8226 --- /dev/null +++ b/docs/global_licensing.rst @@ -0,0 +1,215 @@ +=========================== +Taler licensing information +=========================== + +This file gives an overview of all Taler component's licensing and of +runtime dependencies thereof. For "component" here is meant a set of +source files which can be retrieved from a single repository. If +components consist of sources under different licensing regimes, i.e. +because we want to enable third party developments to easily integrate +with Taler, those are described as well. + +All components are generally released under Lesser GPL, GPL or Affero +GPL. The main strategy is for libraries that third parties may need +to integrate with Taler to be under LGPL, standalone binaries and +testcases to be under GPL, and Web servers implementing Web services +to be under AGPL. + ++++++++++++++++++++++++++ +API (git://taler.net/api) ++++++++++++++++++++++++++ + +The specification has been jointly developed by INRIA and by individuals +being under the juridical subject called 'GNUnet e.V.'. For each source +file, the header indicated whose is holding the copyright, since some +parts have been taken "verbatim" from the GNUnet e.V. foundation, and +some other have been developed at INRIA "ex novo". + +Generally, GNU GPLv3 license is used for them; see COPYING.GPL. + + +-------------------- +Runtime dependencies +-------------------- +This component has no runtime dependencies as it is supposed to generate +HTML. + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++ +Firefox/Android/Python Wallet (git://taler.net/wallet) +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +This project includes contributions from INRIA and GNUnet +e.V. developers. Please refer to each source file to obtain +information about the copyright holder. The GNU GPLv3 is used as the +license for Wallets. Some components may be under the LGPL. + +-------------------- +Runtime dependencies +-------------------- + +The following list encompasses all the runtime dependencies for this +project, and gives the copyright holder for each of them: + +* libgnunetutil: GPLv3+, GNUnet e.V. +* libgnunetjson: GPLv3+, GNUnet e.V. +* libgcrypt: LGPL, Free Software Foundation +* libunistring: LGPL, Free Software Foundation +* Python: Python Software Foundation License, LGPL-Compatible, Python Software Foundation +* Mozilla Firefox: Mozilla Public License, LGPL-Compatible, Mozilla Foundation + + ++++++++++++++++++++++++++++++++++++++++++++++++++++ +WebExtensions Wallet (git://taler.net/wallet-webex) ++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The TypeScript code was developed 100% at INRIA, but the project +involves compiling libgnunetutil and libtalerutil to JavaScript, and +thus depends on software from GNUnet e.V. + +Each source carries its own copyright holder(s), but it is generally +licensed under GPLv3+. + +-------------------- +Runtime dependencies +-------------------- + +The following list encompasses all the runtime dependencies for this +project, and gives the copyright holder for each of them: + +* libgnunetutil: GPLv3+, GNUnet e.V. +* libgnunetjson: GPLv3+, GNUnet e.V. +* libgcrypt: LGPL, Free Software Foundation +* libunistring: LGPL, Free Software Foundation + +Note that these dependencies are compiled into the extension and do +not appear as separate binary files. + + ++++++++++++++++++++++++++++++++++++ +Merchant (git://taler.net/merchant) ++++++++++++++++++++++++++++++++++++ + +This project contains code under two different licenses, and whose +copyright is held by INRIA and/or GNUnet e.V.. Please refer to each +source file to know which party holds the copyright. + +Source files are located in the following directories: + +* src/lib/ +* src/backend/ +* src/backenddb/ +* src/include/ +* src/tests/ +* examples/blog/ +* examples/shop/ +* copylib/ + +In examples/blog/articles/ we included a book by Richard Stallman. +It comes with its own permissive license (see COPYING in the +directory). + + +The merchant's backend (i.e. all the code in src/backend/) is under +the GNU Affero GPL as it depends on libgnunetutil. Note that the use +of the Affero GPL has little impact as the backend is not supposed to +be directly accessible to the Internet). The license for this code is +in COPYING.GPL and COPYING.AGPL. + +The merchant's frontend logic (i.e. JavaScript interacting with +the wallet, sample code for a shop) is under the GNU LGPL (but +we may choose to change this to be in the public domain or +BSD-licensed if necessary; the code is so short that there is +anyway the question whether it is copyrightable). Under this same +license, it comes the merchant library (src/lib/) as it can be linked +with more diverse licensed software. The license text for this code +is in COPYING.LGPL. + + + +-------------------- +Runtime dependencies +-------------------- + +The following list encompasses all the runtime dependencies for this +project, and gives the copyright holder for each of them: + +* libjansson: MIT License, AGPL- and LGPL-Compatible, owned by Petri Lehtinen and other individuals +* libgcrypt: LGPL, owned by Free Software Foundation +* postgresql: PostgreSQL License, AGPL- and LGPL-Compatible, owned by The PostgreSQL Global Development Group +* libgnunetutil (in all of its variants): GPLv3+, owned by GNUnet e.V. +* PHP: PHP License, AGPL- and LGPL-Compatible, owned by The PHP Group + ++++++++++++++++++++++++++++ +Bank (git://taler.net/bank) ++++++++++++++++++++++++++++ + +--------- +Licensing +--------- + +This project has been developed by INRIA. For each source file, the +header indicated whose is holding the copyright. The licensing plan +for the bank is to use the Affero GPLv3+. + +Source files of interest are located in the following directories: +(The repository holds also scaffolded files autogenerated by Django, +which do not have legal significance in this context.) + +* TalerBank/Bank/ +* TalerBank/Bank/templates/ +* TalerBank/my-static/ +* website/ + +-------------------- +Runtime dependencies +-------------------- + +The following list encompasses all the runtime dependencies for this +project, and gives the copyright holder for each of them: + +* Django: BSD License, AGPL-Compatible, owned by Django Software Foundation +* validictory: BSD License, AGPL-Compatible, owned by James Turk +* django-simple-math-captcha: Apache Software License, LGPL-Compatible (FIXME), Brandon Taylor +* requests: Apache2 License, AGPL-Compatible, owned by Kenneth Reitz +* Python: Python Software Foundation License, AGPL-Compatible, Python Software Foundation +* PHP: PHP License, AGPL-Compatible, owned by The PHP Group + + +.. _exchange-repo: + ++++++++++++++++++++++++++++++++++++ +Exchange (git://taler.net/exchange) ++++++++++++++++++++++++++++++++++++ + +This component is based on code initially developed in Munich for +GNUnet e.V. Most recent improvements and maintenance has been done at +Inria. The copyright is thus shared between both institutions. + +The licensing for exported libraries to access the exchange is LGPL, +the exchange itself is under AGPL, and testcases and standalone +binaries are under GPL. + + +-------------------- +Runtime dependencies +-------------------- + +The following list encompasses all the runtime dependencies for this +project, and gives the copyright holder for each of them: + +* libjansson: MIT License, AGPL- and LGPL-Compatible, owned by Petri Lehtinen and other individuals +* libgcrypt: LGPL, owned by Free Software Foundation +* postgresql: PostgreSQL License, AGPL- and LGPL-Compatible, owned by The PostgreSQL Global Development Group +* libgnunetutil (in all of its variants): GPLv3+, owned by GNUnet e.V. +* libgnunetjson: GPLv3+, GNUnet e.V. + + ++++++++++++++++++++++++++++++++++++++++++ +Web includes (git://taler.net/web-common) ++++++++++++++++++++++++++++++++++++++++++ + +All copyright owned by INRIA (but questionable whether creativity +threshold for copyright is even met). + +Sources are licensed under the GNU LGPL. diff --git a/docs/glossary.rst b/docs/glossary.rst new file mode 100644 index 00000000..d9a6cfa7 --- /dev/null +++ b/docs/glossary.rst @@ -0,0 +1,106 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016 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 Florian Dold + @author Christian Grothoff + +.. _glossary: + +============== +Taler Glossary +============== + +.. glossary:: + + auditor + trusted third party that verifies that the exchange is operating correctly + + bank + traditional financial service provider who offers wire :term:`transfers ` between accounts + + coin + coins are individual token representing a certain amount of value, also known as the :term:`denomination` of the coin + + contract + specification of the details of a transaction, specifies the payment obligations for the customer (i.e. the amount), the deliverables of the merchant and other related information, such as deadlines or locations + + denomination + unit of currency, specifies both the currency and the face value of a :term:`coin` + + denomination key + RSA key used by the exchange to certify that a given :term:`coin` is valid and of a particular :term:`denomination` + + deposit + operation by which a merchant passes coins to an exchange, expecting the exchange to credit his :term:`bank` account in the future using a wire :term:`transfer` + + dirty + a :term:`coin` is dirty if its public key may be known to an entity other than the customer, thereby creating the danger of some entity being able to link multiple transactions of coin's owner if the coin is not refreshed first + + extension + implementation of a :term:`wallet` for browsers + + fresh coin + a :term:`coin` is fresh if its public key is only known to the customer + + master key + offline key used by the exchange to certify denomination keys and message signing keys + + message signing key + key used by the exchange to sign online messages, other than coins + + owner + a :term:`coin` is owned by the entity that knows the private key of the coin + + proof + message that cryptographically demonstrates that a particular claim is correct + + reserve + funds set aside for future use; either the balance of a customer at the exchange ready for :term:`withdrawal`, or the funds kept in the exchange's bank account to cover obligations from coins in circulation + + refreshing + operation by which a :term:`dirty` :term:`coin` is converted into one or more :fresh: coins + + refund + operation by which a merchant steps back from the right to funds that he obtained from a :term:`deposit` operation, giving the right to the funds back to the customer + + sharing + users can share ownership of a :term:`coin` by sharing access to the coin's private key, thereby allowing all co-owners to spend the coin at any time. + + signing key + see message signing key. + + spending + operation by which a customer gives a merchant the right to :term:`deposit` coins in return for merchandise + + transfer + method of sending funds between :term:`bank` accounts + + transaction + method by which ownership is exclusively transferred from one entity to another + + transaction id + unique number by which a merchant identifies a :term:`transaction` + + wallet + software running on a customer's computer; withdraws, stores and spends coins + + wire transfer + see :term:`transfer` + + wire transfer identifier + subject of a wire :term:`transfer`; usually a random string to uniquely identify the :term:`transfer` + + withdrawal + operation by which a :term:`wallet` can convert funds from a reserve to fresh coins diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..a4982149 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,104 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016 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 + +GNU Taler Documentation +======================= + +We are building an anonymous, taxable payment system using modern +cryptography. Customers will use traditional money transfers to send +money to a digital Exchange and in return receive (anonymized) digital +cash. Customers can use this digital cash to anonymously pay +Merchants. Merchants can redeem the digital cash for traditional +money at the digital Exchange. As Merchants are not anonymous, they can +be taxed, enabling income or sales taxes to be withheld by the state +while providing anonymity for Customers. + +Cryptography is used to ensure that none of the participants can +defraud the others without being detected immediately; however, in +practice a fradulent Exchange might go bankrupt instead of paying the +Merchants and thus the Exchange will need to be audited regularly like +any other banking institution. + +The system will be based on free software and open protocols. + +In this document, we describe the REST-based APIs between the various +components, internal architecture of key components, and how to get them +installed. + +----------------- +Operator Handbook +----------------- + +The *Operator Handbook* is for people who want to run a exchange or a merchant. +It focuses on how to install, configure and run the required software. + +.. toctree:: + :maxdepth: 2 + + global_licensing + configuration-basics + operate-exchange + operate-merchant + versioning + +------------------------ +Web Integration Handbook +------------------------ + +The *Web Integration Handbook* is for those who want to interact with Taler +wallets on their own website. Integrators will also have to be familiar with +the material covered in the *Operator Handbook*. + + +.. toctree:: + :maxdepth: 2 + + integration-general + integration-bank + integration-merchant + example-essay-store + +------------------ +Developer Handbook +------------------ + +The *Developer Handbook* brings developers up to speed who want to hack on the +core components of the Taler reference implementation. + +.. toctree:: + :maxdepth: 2 + + dev-talerdotnet + dev-wallet-wx + dev-exchange + dev-merchant + deployment.rst + releases.rst + +------------------ +Indices and tables +------------------ + +.. toctree:: + :hidden: + + glossary + +* :doc:`glossary` +* :ref:`search` diff --git a/docs/operate-exchange.rst b/docs/operate-exchange.rst new file mode 100644 index 00000000..874b837c --- /dev/null +++ b/docs/operate-exchange.rst @@ -0,0 +1,246 @@ +.. + 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 + +====================== +Operating the Exchange +====================== + ++++++++++++++ +Configuration ++++++++++++++ + +The following data and facilities have to be set up, in order to run an exchange: + +* Keying +* Serving +* Currency +* Bank account +* Coins +* Database + +In this document, we assume that ``$HOME/.config/taler.conf`` is being customized. + +------ +Keying +------ + +The exchange works with three types of keys: + +* `master key` +* `sign keys` +* `denomination keys` (see section `Coins`) + +`master key`: in section `[exchange]`, edit the two following values: + +* `master_priv_file`: Path to the exchange's master private file. +* `master_public_key`: Must specify the exchange's master public key. + +`sign keys`: the following two options under `[exchange_keys]` section control `sign keys`: + +* `signkey_duration`: How long should one signing key be used? +* `lookahead_sign`: How much time we want to cover with our `signkeys`? Note that if `signkey_duration` is bigger than `lookahead_sign`, `taler-exchange-keyup` will generate a quantity of `signkeys` which is sufficient to cover all the gap. See :ref:`keys-duration`. + +------- +Serving +------- + +The exchange can serve HTTP over both TCP and UNIX domain socket. It needs this +configuration *twice*, because it opens one connection for ordinary REST calls, and one +for "/admin" and "/test" REST calls, because the operator may want to restrict the access to "/admin". + +The following values are to be configured under the section `[exchange]` and `[exchange-admin]`: + +* `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----). + +The exchange can be started with the `-D` option to disable the administrative +functions entirely. It is recommended that the administrative API is only +accessible via a properly protected UNIX domain socket. + +-------- +Currency +-------- + +The exchange supports only one currency. This data is set under the respective +option `currency` in section `[taler]`. + +------------ +Bank account +------------ + +Wireformat +^^^^^^^^^^ + +The wireformat is the protocol to be used between the exchange and the banks. +The option is `wireformat`, under section `[exchange]`. The exchange currently supports +the `test` wireformat. This wireformat is used for testing the system against a fictional bank. + +.. note:: + The SEPA wireformat is work in progress. + +Incoming +^^^^^^^^ +The bank account where the exchange gets money from customers is configured under +the section `[exchange-wire-incoming-X]`, where `X` matches the value given to the +option `wireformat`. This section contains only one option: `X_response_file`, which +takes the path to a text file containing the exchange's bank account details in JSON +format. + +The command line tool `taler-exchange-wire` is used to create such a file. +For example, the utility may be invoked as follows:: + + $ taler-exchange-wire -j '{"name": "The Exchange", "account_number": 10, "bank_uri": "https://bank.demo.taler.net", "type": "test"}' -t test -o exchange.json + +Note that the value given to option `-t` must match the value in the JSON's field ``"type"``. + +The generated file will be echoed by the exchange when serving :ref:`/wire ` requests. + +Outgoing +^^^^^^^^ + +This exchange's bank account is used to give money to merchants, after successful :ref:`deposits ` +operations. If `test` is the chosen wireformat, the outcoming bank account is configured by the following +options under `[exchange-wire-outcoming-test]`: + + * `exchange_account_numer`: which bank account number has the exchange + * `bank_uri`: base URL of the bank hosting the exchange bank account + +.. note:: + The rationale behind having two 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. + +-------- +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 `db_conn_str`, under section `[exchangedb-BACKEND]`. For example, the demo exchange is configured as follows: + +.. code-block:: text + + [exchange] + ... + db = postgres + ... + + [exchangedb-postgres] + db_conn_str = postgres:///talerdemo + +------------------------- +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 +------------- + +Both `signkeys` and `denom keys` have a :ref:`starting date `. The option `lookahead_provide`, under section `[exchange_keys]`, is such that only keys +whose starting date is younger than `lookahead_provide` will be issued by the exchange. + +.. _exchange-install: + +++++++++++++ +Installation +++++++++++++ + +Please install the following packages before proceeding with the exchange compilation. + +* 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 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://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``. + +To download and install the GNU Taler exchange, proceeds 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. + ++++++ +Other ++++++ + +------------------ +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. diff --git a/docs/operate-merchant.rst b/docs/operate-merchant.rst new file mode 100644 index 00000000..484d6eba --- /dev/null +++ b/docs/operate-merchant.rst @@ -0,0 +1,212 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2014, 2015, 2016 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 + @author Florian Dold + +============================== +Operating the Merchant Backend +============================== + ++++++++++++++ +Configuration ++++++++++++++ + +The following data and facilities have to be set up, in order to run a merchant backend: + +* Serving +* Currency +* Database +* Exchanges +* Keying +* Bank account +* Instances + +In this document, we assume that ``$HOME/.config/taler.conf`` is being customized. + +------- +Serving +------- + +The merchant backend can serve HTTP over both TCP and UNIX domain socket. + +The following values are to be configured under the section `[merchant]`: + +* `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 +-------- + +The merchant backend supports only one currency. This data is set under the respective +option `currency` in section `[taler]`. + +-------- +Database +-------- + +The option `db` under section `[merchant]` gets the DB backend's name the merchant +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_MERCHANTDB_POSTGRES_CONFIG`. +* via configuration option `config`, under section `[merchantdb-BACKEND]`. For example, the demo merchant is configured as follows: + +.. code-block:: text + + [merchant] + ... + db = postgres + ... + + [merchantdb-postgres] + config = postgres:///talerdemo + +--------- +Exchanges +--------- + +The options `uri` and `master_key`, under section `[merchant-exchange-MYEXCHANGE]`, let +the merchant add the exchange `MYEXCHANGE` among the exchanges the merchant wants to work +with. `MYEXCHAGE` is just a mnemonic name chosen by the merchant (which is not currently used +in any computation), and the merchant can add as many exchanges as it is needed. +`uri` is the exchange's base URL. Please note that a valid `uri` complies with the following +pattern:: + + schema://hostname/ + +`master_key` is the base32 encoding of the exchange's master key (see :ref:`/keys `). +In our demo, we use the following configuration:: + + [merchant-exchange-test] + URI = https://exchange.test.taler.net/ + MASTER_KEY = CQQZ9DY3MZ1ARMN5K1VKDETS04Y2QCKMMCFHZSWJWWVN82BTTH00 + +------ +Keying +------ + +The option `keyfile` under section `[merchant-instance-default]` is the path to the +merchant's :ref:`default instance ` private key. This key is needed to +sign certificates and other messages sent to wallets and exchanges. +To generate a 100% compatible key, it is recommended to use the ``gnunet-ecc`` tool. + +------------ +Bank account +------------ + +This piece of information is used when the merchant redeems coins to the exchange. +That way, the exchange will know to which bank account it has to transfer real money. +The merchant must specify which system it wants receive wire transfers with. We support +a `test` wire format so far, and supporting `SEPA` is among our priorities. + +The wire format is specified in the option `wireformat` under section `[merchant]`, +and the wire details are given via a JSON file, whose path must be indicated in the +option `X_response_file` under section `[default-wireformat]`, where `X` matches +the chosen wireformat. In our demo, we have:: + + [merchant] + .. + wireformat = test + .. + + [merchant-instance-wireformat-default] + test_response_file = ${TALER_CONFIG_HOME}/merchant/wire/test.json + +The file `test.json` obeys to the following specification + +.. code-block:: tsref + + interface WireDetails { + // matches wireformat + type: string; + + // base URL of the merchant's bank + bank_uri: string; + + // merchant's signature (unused, can be any value) + signature: string; + + // merchant's account number at the bank + account_number: Integer; + + // the salt (unused, can be any value) + salt: any; + } + +As an example, `test.json` used in our demo is shown below:: + + { + "type": "test", + "bank_uri": "https://bank.test.taler.net/", + "sig": "MERCHANTSIGNATURE", + "account_number": 6, + "salt": "SALT" + } + + + +.. _instances-lab: + +--------- +Instances +--------- + +In Taler, multiple shops can rely on the same :ref:`merchant backend `. +In Taler terminology, each of those shops is called `(merchant) instance`. Any instance +is defined by its private key and its wire details. In order to add the instance `X` to +the merchant backend, we have to add the sections `[merchant-instance-X]` and `[X-wireformat]`, +and edit them as we did for the `default` instance. For example, in our demo we add the +instance `Tor` as follows:: + + [merchant-instance-Tor] + KEYFILE = ${TALER_DATA_HOME}/merchant/tor.priv + + .. + + [merchant-instance-wireformat-Tor] + TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/merchant/wire/tor.json + +Please note that :ref:`Taler messagging` is designed so that the merchant +frontend can instruct the backend on which instance has to be used in the various operations. +This information is optional, and if not given, the backend will act as the `default` instance. + +++++++++++++ +Installation +++++++++++++ + + + + + +In order to compile your merchant backend, you firstly need to install the GNU Taler +exchange. As of other dependencies, the merchant backend needs exactly the same ones +as the exchange does. Follow :ref:`those instructions ` to build +everything needed. + +Assuming all the dependencies have been correctly installed, we can now build the +merchant backend using the following commands:: + + $ 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 diff --git a/example-essay-store.rst b/example-essay-store.rst deleted file mode 100644 index 19428019..00000000 --- a/example-essay-store.rst +++ /dev/null @@ -1,615 +0,0 @@ -.. - This file is part of GNU TALER. - - Copyright (C) 2014, 2015, 2016 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 - -==================== -Example: Essay Store -==================== - -This section shows how to set up a merchant :ref:`frontend `, and is -inspired by our demonstration shop running at `https://shop.demo.taler.net/`. -It is recommended that the reader is already familiar with the -:ref:`payment protocol and terminology `. - -The code we are going to describe is available at -https://git.taler.net/merchant-frontends.git/tree/talerfrontends/blog -and is implemented in Python+Flask. - -The frontend shows a list of buyable articles in its homepage, and once the -user clicks one of them, they will either get the Taler :ref:`contract ` -or a credit card paywall if they don't have the Taler wallet. - -Each article thus links to a `offer URL`, whose layout is shown below. - - `https://shop.demo.taler.net/essay/Appendix_A:_A_Note_on_Software` - -Once the server side logic receives a request for a offer URL, it needs to -instruct the wallet to retrieve a Taler contract. This action can be taken -either with or **without** the use of JavaScript, see the next section. - ------------------------ -Triggering the contract ------------------------ - -It is important to note that the contract is not returned simply -as the offer URL's response, but rather the frontend `instructs` -the browser on how to retrieve the contract. That is needed for -the right handling of the cases where the wallet is not installed. - -.. note:: - - The code samples shown below are intentionally "incomplete", as often - one function contains logic for multiple actions. Thus in order to not - mix concepts form different actions under one section, parts of code not - related to the section being documented have been left out. - -**With JavaScript** - -In this case, the objective is to call the function ``taler.offerContractFrom()`` into the user browser, which will then retrieve the -contract. In order to do that, we return a HTML page, whose -template is in ``talerfrontends/blog/templates/purchase.html``, -that imports ``taler-wallet-lib.js``, so that the function -``taler.offerContractFrom()`` can be invoked into the user's -browser. - -The server side handler for a offer URL needs to render ``purchase.html`` by passing -the right parameters to ``taler.offerContractFrom()``. - -The rendering is done by the ``article`` function at ``talerfrontends/blog/blog.py``, -and is done by Flask's ``render_template()``, see below. - -.. sourcecode:: python - - # 'name' is the article name, and is set to the right value - # by Flask - # The 'data' parameter is used to send images along - # the articles, however its use is beyond the scope of - # this survey. - def article(name, data=None): - ... - ... - - return render_template('templates/purchase.html', - article_name=name, - no_contract=1, - contract_url=quote(contract_url), - data_attribute="data-taler-contractoffer=%s" % contract_url) - -After the rendering, (part of) ``purchase.html`` will look like shown below. - -.. sourcecode:: html - - ... - - - ... - - - ... - ... - -
-

- Oops, it looks like you don't have a Taler wallet installed. Why don't you enter - all your credit card details before reading the article? You can also - use GNU Taler to complete the purchase at any time. -

- -
- First name

- Family name

- Age

- Nationality

- Gender
Male - CC number

- Female
-
-
- -
-
- -
- Processing payment with GNU Taler, please wait -
- ... - -The script ``purchase.js`` is now in charge of implementing the behaviour we seek. -It needs to register two handlers: one called whenever the wallet is detected in the -browser, the other if the user has no wallet installed. - -That is done with: - -.. sourcecode:: javascript - - taler.onPresent(handleWalletPresent); - taler.onAbsent(handleWalletAbsent); - -Note that the ``taler`` object is exported by ``taler-wallet-lib.js``, and contains all -is needed to communicate with the wallet. - - -``handleWalletAbsent`` doesn't need to do much: it has to only hide the "please wait" -message and uncover the credit card pay form. See below. - -.. sourcecode:: javascript - - function handleWalletAbsent() { - // Hide "please wait" message - document.getElementById("talerwait").style.display = "none"; - // Uncover credit card pay form - document.body.style.display = ""; - } - -On the other hand, ``handleWalletPresent`` needs to firstly hide the credit card -pay form and show the "please wait" message. After that, it needs to fetch the -contract URL from the responsible ``meta`` tag, and finally invoke ``taler.offerContractFrom()`` using it. See below both parts. - -.. sourcecode:: javascript - - function handleWalletPresent() { - // Hide credit card paywall - document.getElementById("ccfakeform").style.display = "none"; - // Show "please wait" message - document.getElementById("talerwait").style.display = ""; - ... - ... - // Fetch contract URL from 'meta' tag. - let contract_url = document.querySelectorAll("[name=contract_url]")[0]; - // If this call is successful, it will obtain the contract, - // hand it to the wallet, so the wallet can eventually - // show it to the user. - taler.offerContractFrom(decodeURIComponent(contract_url.getAttribute("value"))); - ... - } - -.. note:: - - In order to get our code validated by W3C validators, we can't have inline - JavaScript in our pages, we are forced to import any used script instead. - -**Without JavaScript** - -This case is handled by the function ``article`` defined in -``talerfrontends/blog/blog.py``. Its objective is to set the "402 Payment -Required" HTTP status code, and the HTTP header ``X-Taler-Contract-Url`` -to the actual contract's URL for this purchase. - -Upon returning such a response, the wallet will automatically fetch the -contract from the URL indicated by ``X-Taler-Contract-Url``, and show it -to the user. - -Below is shown how the function ``article`` prepares and returns such a -response. - -.. sourcecode:: python - - # 'name' is the article name, and is set to the right value - # by Flask - # The 'data' parameter is used to send images along - # the articles, however its use is beyond the scope of - # this survey. - def article(name, data=None): - ... - ... - - # Create response. - response = make_response(render_template('templates/fallback.html'), 402) - # Set "X-Taler-Contract-Url" header to the contract's URL. - response.headers["X-Taler-Contract-Url"] = contract_url - return response - -The ``make_response`` function is exported by Flask, so it's beyond the scope -of this document to explain it; however, it returns a "response object" having -the "402 Payment Required" as HTTP status code, and the -HTML file ``talerfrontends/blog/templates/fallback.html`` as the body. -``fallback.html`` contains the credit card pay form, so that if the wallet is -not installed, the browser would keep that page shown. - -``contract_url`` is defined in the earlier steps of the same function; however, -in this example it looks like: - - `https://shop.demo.taler.net/essay/generate-contract?article_name=Appendix_A:_A_Note_on_Software`. - -The frontend will also have to provide the contract. That is done -by the handler ``generate_contract``, defined in -``talerfrontends/blog/blog.py``. See below. - -.. sourcecode:: python - - def generate_contract(): - now = int(time.time()) - tid = random.randint(1, 2**50) - article_name = expect_parameter("article_name") - contract = make_contract(article_name=article_name, tid=tid, timestamp=now) - contract_resp = sign_contract(contract) - logger.info("generated contract: %s" % str(contract_resp)) - return jsonify(**contract_resp) - - -Its task is to feed the ``make_contract`` subroutine with all the -values it needs to generate a contract. Those values are: the timestamp -for the contract, the transaction ID, and the article name; respectively, -``now``, ``tid``, and ``article_name``. - -After ``make_contract`` returns, the variable ``contract`` will hold a -`dict` type that complies with a contract :ref:`proposition `. -We then call ``sign_contract`` feeding it with the proposition, so that -it can forward it to the backend and return it signed. Finally we return -the signed proposition, complying with the :ref:`Offer ` object. - -For simplicity, any article costs the same price, so the frontend -doesn't need to map articles to prices. - -Both ``make_contract`` and ``sign_contract`` are defined in -``talerfrontends/blog/helpers.py``. - -At this point, the user can accept the contract, which triggers the wallet -to visit the fulfillment page. The main logic for a fulfillment page handler -is to (1) return the claimed product, if it has been paid, or (2) instruct the -wallet to send the payment. - ------------------ -Fulfillment logic ------------------ - -The state accounts for a product being paid or not, so the fulfillment handler -will firstly check that: - -.. sourcecode:: python - - # 'name' is the article name, and is set to the right value - # by Flask - # The 'data' parameter is used to send images along - # the articles, however its use is beyond the scope of - # this survey. - def article(name, data=None): - # Get list of payed articles from the state - payed_articles = session.get("payed_articles", []) - - if name in payed_articles: - ... - # The articles has been paid, so return it to the - # customer. - return send_file(get_article_file(article)) - ... - -In case the article has not been paid yet, the fulfillment handler needs -to `reconstruct` the contract, in order to get a precise reference about the -purchase in being served. - -All the information needed to reconstruct the contract is contained in the -fulfillment URL parameters. See below the URL layout: - - `https://shop.demo.taler.net/essay/Appendix_A:_A_Note_on_Software?uuid=×tamp=tid=` - -The way the contract is reconstructed is exactly the same as it was generated -in the previous steps: we need to call ``make_contract`` to get the original -:ref:`proposition ` and then ``sign_contract``. Recall that aside -from allowing the backend to add missing fields to the proposition, ``sign_contract`` -returns the contract hashcode also, that we should compare with the ``uuid`` -parameter provided by the wallet. - -In our blog, all the fulfillment logic is implemented in the function ``article``, -defined in ``talerfrontends/blog/blog.py``. It is important to note that this -function is `the same` function that runs the offer URL; in fact, as long as your -URL design allows it, it is not mandatory to split up things. In our example, the -offer URL differs from the fulfillment URL respect to the number (and type) of -parameters, so the ``article`` function can easily decide whether it has to handle -a "offer" or a "fulfillment" case. See below how the function detects the right -case and reconstructs the contract. - -.. sourcecode:: python - - # 'name' is the article name, and is set to the right value - # by Flask - # The 'data' parameter is used to send images along - # the articles, however its use is beyond the scope of - # this survey. - def article(name, data=None): - - ... - hc = request.args.get("uuid") - tid_str = request.args.get("tid") - timestamp_str = request.args.get("timestamp") - if hc is None or tid_str is None or timestamp_str is None: - # Offer URL case. - contract_url = make_url("/generate-contract", ("article_name",name)) - ... # Go on operating the offer URL and return - - # Fulfillment URL case from here on. - try: - tid = int(tid_str) - except ValueError: - raise MalformedParameterError("tid") - try: - timestamp = int(timestamp_str) - except ValueError: - raise MalformedParameterError("timestamp") - - restored_contract = make_contract(article_name=name, tid=tid, timestamp=timestamp) - contract_resp = sign_contract(restored_contract) - - # Return error if uuid mismatch with the hashcode coming from the backend - if contract_resp["H_contract"] != hc: - e = jsonify(error="contract mismatch", was=hc, expected=contract_resp["H_contract"]) - return e, 400 - - # We save the article's name in the state since after - # receiving the payment this value will point to the - # article to be delivered to the customer. Note how the - # contract's hashcode is used to index the state. - session[hc] = si = session.get(hc, {}) - si['article_name'] = name - - -After a successful contract reconstruction, the handler needs to instruct -the wallet to actually send the payment. There are as usual two ways this -can be accomplished: with and without JavaScript. - -**With JavaScript** - -.. - Mention that the template is the same we used for a offer URL! - -We return a HTML page, whose template is in -``talerfrontends/blog/templates/purchase.html``, that imports ``taler-wallet-lib.js``, -so that the function ``taler.executePayment()`` can be invoked into the user's -browser. - -The fulfillment handler needs to render ``purchase.html`` so that the right -parameters get passed to ``taler.executePayment()``. - -See below how the function ``article`` does the rendering. - -.. sourcecode:: python - - # 'name' is the article name, and is set to the right value - # by Flask - # The 'data' parameter is used to send images along - # the articles, however its use is beyond the scope of - # this survey. - def article(name, data=None): - - ... - ... - - return render_template('templates/purchase.html', - hc=hc, - pay_url=quote(pay_url), - offering_url=quote(offering_url), - article_name=name, - no_contract=0, - data_attribute="data-taler-executecontract=%s,%s,%s" % (hc, pay_url, offering_url)) - -After the rendering, (part of) ``purchase.html`` will look like shown below. - -.. sourcecode:: html - - ... - - - ... - - - - - - ... - ... - -
-

- Oops, it looks like you don't have a Taler wallet installed. Why don't you enter - all your credit card details before reading the article? You can also - use GNU Taler to complete the purchase at any time. -

- -
- -
-
- -
- Processing payment with GNU Taler, please wait -
- ... - -The script ``purchase.js`` is now in charge of calling ``taler.executePayment()``. -It will try to register two handlers: one called whenever the wallet is detected in the -browser, the other if the user has no wallet installed. - -That is done with: - -.. sourcecode:: javascript - - taler.onPresent(handleWalletPresent); - taler.onAbsent(handleWalletAbsent); - -.. note:: - - So far, the template and the imported script (``purchase.js``) - are exactly the same as the offer URL case, since we use them - for both cases. See below how the script distinguishes "offer" - from "fulfillment" case. - -Note that the ``taler`` object is exported by ``taler-wallet-lib.js``, and contains all -is needed to communicate with the wallet. - - -``handleWalletAbsent`` doesn't need to do much: it has to only hide the "please wait" -message and uncover the credit card pay form. See below. - -.. sourcecode:: javascript - - function handleWalletAbsent() { - // Hide "please wait" message - document.getElementById("talerwait").style.display = "none"; - // Uncover credit card pay form - document.body.style.display = ""; - } - -On the other hand, ``handleWalletPresent`` needs to firstly hide the credit card -pay form and show the "please wait" message. After that, it needs to fetch the -needed parameters from the responsible ``meta`` tags, and finally invoke -``taler.offerContractFrom()`` using those parameters. See below its whole definition. -Note, that since we are in the fulfillment case, the credit card pay form is `almost` -useless, as it is highly unlikely that the wallet is not installed. - -.. sourcecode:: javascript - - function handleWalletPresent() { - // Hide the credit card pay form - document.getElementById("ccfakeform").style.display = "none"; - // Show "please wait" message - document.getElementById("talerwait").style.display = ""; - - // The `no_contract` value is provided by the function `article` via a - // 'meta' tag in the template. When this value equals 1, then we are in the - // "offer" URL case, otherwise we are in the "fulfillment" URL case. - let no_contract = document.querySelectorAll("[name=no_contract]")[0]; - if (Number(no_contract.getAttribute("value"))) { - // "Offer" case - let contract_url = document.querySelectorAll("[name=contract_url]")[0]; - taler.offerContractFrom(decodeURIComponent(contract_url.getAttribute("value"))); - } - else { - // "Fulfillment" case. - let hc = document.querySelectorAll("[name=hc]")[0]; - let pay_url = document.querySelectorAll("[name=pay_url]")[0]; - let offering_url = document.querySelectorAll("[name=offering_url]")[0]; - taler.executePayment(hc.getAttribute("value"), - decodeURIComponent(pay_url.getAttribute("value")), - decodeURIComponent(offering_url.getAttribute("value"))); - } - } - -Once the browser executes ``taler.executePayment(...)``, the wallet will send the coins -to ``pay_url``. Once the payment succeeds, the wallet will again visit the -fulfillment URL, this time getting the article thanks to the "payed" status set by -the ``pay_url`` handler. - -**Without JavaScript** - -This case is handled by the function ``article`` defined in -``talerfrontends/blog/blog.py``. Its objective is to set the "402 Payment -Required" HTTP status code, along with the HTTP headers ``X-Taler-Contract-Hash``, -``X-Taler-Pay-Url``, and ``X-Taler-Offer-Url``. - -.. - FIXME: - Are those three parameters anywhere, at least 'kindof' introduced? - -Upon returning such a response, the wallet will automatically send the -payment to the URL indicated in ``X-Taler-Pay-Url``. - -The excerpt below shows how the function ``article`` prepares and returns such a -response. - -.. sourcecode:: python - - # 'name' is the article name, and is set to the right value - # by Flask - # The 'data' parameter is used to send images along - # the articles, however its use is beyond the scope of - # this survey. - def article(name, data=None): - ... - - # 'make_response' is exported by Flask. It returns a - # "response object" with customizable status code, HTTP - # headers and body - response = make_response(render_template('templates/fallback.html'), 402) - response.headers["X-Taler-Contract-Hash"] = hc - response.headers["X-Taler-Pay-Url"] = pay_url - response.headers["X-Taler-Offer-Url"] = offering_url - return response - -The template ``fallback.html`` contains the credit card pay form, which will be -used in the rare case where the wallet would not be detected in a fulfillment -session. Once the payment succeeds, the wallet will again visits the -fulfillment URL, this time getting the article thanks to the "payed" status set by -the ``pay_url`` handler. - ---------- -Pay logic ---------- - -The pay handler for the blog is implemented by the function -``pay`` at ``talerfrontends/blog/blog.py``. Its main duty is -to receive the :ref:`deposit permission ` -from the wallet, forward it to the backend, and return the outcome -to the wallet. See below the main steps of its implementation. - -.. sourcecode:: python - - def pay(): - # Get the uploaded deposit permission - deposit_permission = request.get_json() - - if deposit_permission is None: - e = jsonify(error="no json in body") - return e, 400 - - # Pick the contract's hashcode from deposit permission - hc = deposit_permission.get("H_contract") - - # Return error if no hashcode was found - if hc is None: - e = jsonify(error="malformed deposit permission", hint="H_contract missing") - return e, 400 - - # Get a handle to the state for this contract, using the - # hashcode from deposit permission as the index - si = session.get(hc) - - # If no session was found for this contract, then either it - # expired or one of the hashcodes (the one we got from - # reconstructing the contract in the fulfillment handler, - # and the one we just picked from the deposit permission) - # is bogus. Note how using the contract's hashcode as index - # makes harder for the wallet to use different hashcodes - # in different steps of the protocol. - if si is None: - e = jsonify(error="no session for contract") - return e, 400 - - # Forward the deposit permission to the backend - r = requests.post(urljoin(BACKEND_URL, 'pay'), json=deposit_permission) - - # Return error if the backend returned a HTTP status code - # other than 200 OK - if 200 != r.status_code: - raise BackendError(r.status_code, r.text) - - # The payment went through.. - ... - - # Resume the article name - article = si["article_name"] - - # Set the article's state as "payed". This is realized by - # appending it to a *list* of articles the customer is currently - # allowed to read. - payed_articles = session["payed_articles"] = session.get("payed_articles", []) - if article not in payed_articles: - payed_articles.append(article) - - ... - - # Return success - return r.text, 200 diff --git a/exts/tsref.py b/exts/tsref.py deleted file mode 100644 index 8187f67f..00000000 --- a/exts/tsref.py +++ /dev/null @@ -1,233 +0,0 @@ -""" - This file is part of GNU TALER. - Copyright (C) 2014, 2015 GNUnet e.V. and INRIA - TALER 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, 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 -""" - -""" -This extension adds a new lexer "tsref" for TypeScript, which -allows reST-style links inside comments (`LinkName`_), -and semi-automatically adds links to the definition of types. - -For type TYPE, a reference to tsref-type-TYPE is added. - -Known bugs and limitations: - - The way the extension works right now interferes wiht - Sphinx's caching, the build directory should be cleared - before every build. -""" - - -from pygments.util import get_bool_opt -from pygments.token import Name, Comment, Token, _TokenType -from pygments.filter import Filter -from sphinx.highlighting import PygmentsBridge -from sphinx.builders.html import StandaloneHTMLBuilder -from sphinx.pygments_styles import SphinxStyle -from pygments.formatters import HtmlFormatter -from docutils import nodes -from docutils.nodes import make_id -import re - - -_escape_html_table = { - ord('&'): u'&', - ord('<'): u'<', - ord('>'): u'>', - ord('"'): u'"', - ord("'"): u''', -} - - -class LinkingHtmlFormatter(HtmlFormatter): - def __init__(self, **kwargs): - super(LinkingHtmlFormatter, self).__init__(**kwargs) - self._builder = kwargs['_builder'] - - def _fmt(self, value, tok): - cls = self._get_css_class(tok) - href = tok_getprop(tok, "href") - caption = tok_getprop(tok, "caption") - content = caption if caption is not None else value - if href: - value = '%s' % (href, content) - if cls is None or cls == "": - return value - return '%s' % (cls, value) - - def _format_lines(self, tokensource): - """ - Just format the tokens, without any wrapping tags. - Yield individual lines. - """ - lsep = self.lineseparator - escape_table = _escape_html_table - - line = '' - for ttype, value in tokensource: - link = get_annotation(ttype, "link") - - parts = value.translate(escape_table).split('\n') - - if len(parts) == 0: - # empty token, usually should not happen - pass - elif len(parts) == 1: - # no newline before or after token - line += self._fmt(parts[0], ttype) - else: - line += self._fmt(parts[0], ttype) - yield 1, line + lsep - for part in parts[1:-1]: - yield 1, self._fmt(part, ttype) + lsep - line = self._fmt(parts[-1], ttype) - - if line: - yield 1, line + lsep - - -class MyPygmentsBridge(PygmentsBridge): - def __init__(self, builder, trim_doctest_flags): - self.dest = "html" - self.trim_doctest_flags = trim_doctest_flags - self.formatter_args = {'style': SphinxStyle, '_builder': builder} - self.formatter = LinkingHtmlFormatter - - -class MyHtmlBuilder(StandaloneHTMLBuilder): - name = "html-linked" - def init_highlighter(self): - if self.config.pygments_style is not None: - style = self.config.pygments_style - elif self.theme: - style = self.theme.get_confstr('theme', 'pygments_style', 'none') - else: - style = 'sphinx' - self.highlighter = MyPygmentsBridge(self, self.config.trim_doctest_flags) - - def write_doc(self, docname, doctree): - self._current_docname = docname - super(MyHtmlBuilder, self).write_doc(docname, doctree) - - -def get_annotation(tok, key): - if not hasattr(tok, "kv"): - return None - return tok.kv.get(key) - - -def copy_token(tok): - new_tok = _TokenType(tok) - # This part is very fragile against API changes ... - new_tok.subtypes = set(tok.subtypes) - new_tok.parent = tok.parent - return new_tok - - -def tok_setprop(tok, key, value): - tokid = id(tok) - e = token_props.get(tokid) - if e is None: - e = token_props[tokid] = (tok, {}) - _, kv = e - kv[key] = value - - -def tok_getprop(tok, key): - tokid = id(tok) - e = token_props.get(tokid) - if e is None: - return None - _, kv = e - return kv.get(key) - - -link_reg = re.compile(r"`([^`<]+)\s*(?:<([^>]+)>)?\s*`_") - -# Map from token id to props. -# Properties can't be added to tokens -# since they derive from Python's tuple. -token_props = {} - - -class LinkFilter(Filter): - def __init__(self, app, **options): - self.app = app - Filter.__init__(self, **options) - - def filter(self, lexer, stream): - id_to_doc = self.app.env.domaindata.get("_tsref", {}) - for ttype, value in stream: - if ttype in Token.Keyword.Type: - defname = make_id('tsref-type-' + value); - t = copy_token(ttype) - if defname in id_to_doc: - docname = id_to_doc[defname] - href = self.app.builder.get_target_uri(docname) + "#" + defname - tok_setprop(t, "href", href) - - yield t, value - elif ttype in Token.Comment: - last = 0 - for m in re.finditer(link_reg, value): - pre = value[last:m.start()] - if pre: - yield ttype, pre - t = copy_token(ttype) - x1, x2 = m.groups() - if x2 is None: - caption = x1.strip() - id = make_id(x1) - else: - caption = x1.strip() - id = make_id(x2) - if id in id_to_doc: - docname = id_to_doc[id] - href = self.app.builder.get_target_uri(docname) + "#" + id - tok_setprop(t, "href", href) - tok_setprop(t, "caption", caption) - else: - self.app.builder.warn("unresolved link target in comment: " + id) - yield t, m.group(1) - last = m.end() - post = value[last:] - if post: - yield ttype, post - else: - yield ttype, value - - - -def remember_targets(app, doctree): - docname = app.env.docname - id_to_doc = app.env.domaindata.get("_tsref", None) - if id_to_doc is None: - id_to_doc = app.env.domaindata["_tsref"] = {} - for node in doctree.traverse(): - if not isinstance(node, nodes.Element): - continue - ids = node.get("ids") - if ids: - for id in ids: - id_to_doc[id] = docname - - -def setup(app): - from sphinx.highlighting import lexers - from pygments.lexers import TypeScriptLexer - from pygments.token import Name - from pygments.filters import NameHighlightFilter - lexer = TypeScriptLexer() - lexer.add_filter(LinkFilter(app)) - app.add_lexer('tsref', lexer) - app.add_builder(MyHtmlBuilder) - app.connect("doctree-read", remember_targets) diff --git a/global_licensing.rst b/global_licensing.rst deleted file mode 100644 index 7a5e8226..00000000 --- a/global_licensing.rst +++ /dev/null @@ -1,215 +0,0 @@ -=========================== -Taler licensing information -=========================== - -This file gives an overview of all Taler component's licensing and of -runtime dependencies thereof. For "component" here is meant a set of -source files which can be retrieved from a single repository. If -components consist of sources under different licensing regimes, i.e. -because we want to enable third party developments to easily integrate -with Taler, those are described as well. - -All components are generally released under Lesser GPL, GPL or Affero -GPL. The main strategy is for libraries that third parties may need -to integrate with Taler to be under LGPL, standalone binaries and -testcases to be under GPL, and Web servers implementing Web services -to be under AGPL. - -+++++++++++++++++++++++++ -API (git://taler.net/api) -+++++++++++++++++++++++++ - -The specification has been jointly developed by INRIA and by individuals -being under the juridical subject called 'GNUnet e.V.'. For each source -file, the header indicated whose is holding the copyright, since some -parts have been taken "verbatim" from the GNUnet e.V. foundation, and -some other have been developed at INRIA "ex novo". - -Generally, GNU GPLv3 license is used for them; see COPYING.GPL. - - --------------------- -Runtime dependencies --------------------- -This component has no runtime dependencies as it is supposed to generate -HTML. - - -++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Firefox/Android/Python Wallet (git://taler.net/wallet) -++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -This project includes contributions from INRIA and GNUnet -e.V. developers. Please refer to each source file to obtain -information about the copyright holder. The GNU GPLv3 is used as the -license for Wallets. Some components may be under the LGPL. - --------------------- -Runtime dependencies --------------------- - -The following list encompasses all the runtime dependencies for this -project, and gives the copyright holder for each of them: - -* libgnunetutil: GPLv3+, GNUnet e.V. -* libgnunetjson: GPLv3+, GNUnet e.V. -* libgcrypt: LGPL, Free Software Foundation -* libunistring: LGPL, Free Software Foundation -* Python: Python Software Foundation License, LGPL-Compatible, Python Software Foundation -* Mozilla Firefox: Mozilla Public License, LGPL-Compatible, Mozilla Foundation - - -+++++++++++++++++++++++++++++++++++++++++++++++++++ -WebExtensions Wallet (git://taler.net/wallet-webex) -+++++++++++++++++++++++++++++++++++++++++++++++++++ - -The TypeScript code was developed 100% at INRIA, but the project -involves compiling libgnunetutil and libtalerutil to JavaScript, and -thus depends on software from GNUnet e.V. - -Each source carries its own copyright holder(s), but it is generally -licensed under GPLv3+. - --------------------- -Runtime dependencies --------------------- - -The following list encompasses all the runtime dependencies for this -project, and gives the copyright holder for each of them: - -* libgnunetutil: GPLv3+, GNUnet e.V. -* libgnunetjson: GPLv3+, GNUnet e.V. -* libgcrypt: LGPL, Free Software Foundation -* libunistring: LGPL, Free Software Foundation - -Note that these dependencies are compiled into the extension and do -not appear as separate binary files. - - -+++++++++++++++++++++++++++++++++++ -Merchant (git://taler.net/merchant) -+++++++++++++++++++++++++++++++++++ - -This project contains code under two different licenses, and whose -copyright is held by INRIA and/or GNUnet e.V.. Please refer to each -source file to know which party holds the copyright. - -Source files are located in the following directories: - -* src/lib/ -* src/backend/ -* src/backenddb/ -* src/include/ -* src/tests/ -* examples/blog/ -* examples/shop/ -* copylib/ - -In examples/blog/articles/ we included a book by Richard Stallman. -It comes with its own permissive license (see COPYING in the -directory). - - -The merchant's backend (i.e. all the code in src/backend/) is under -the GNU Affero GPL as it depends on libgnunetutil. Note that the use -of the Affero GPL has little impact as the backend is not supposed to -be directly accessible to the Internet). The license for this code is -in COPYING.GPL and COPYING.AGPL. - -The merchant's frontend logic (i.e. JavaScript interacting with -the wallet, sample code for a shop) is under the GNU LGPL (but -we may choose to change this to be in the public domain or -BSD-licensed if necessary; the code is so short that there is -anyway the question whether it is copyrightable). Under this same -license, it comes the merchant library (src/lib/) as it can be linked -with more diverse licensed software. The license text for this code -is in COPYING.LGPL. - - - --------------------- -Runtime dependencies --------------------- - -The following list encompasses all the runtime dependencies for this -project, and gives the copyright holder for each of them: - -* libjansson: MIT License, AGPL- and LGPL-Compatible, owned by Petri Lehtinen and other individuals -* libgcrypt: LGPL, owned by Free Software Foundation -* postgresql: PostgreSQL License, AGPL- and LGPL-Compatible, owned by The PostgreSQL Global Development Group -* libgnunetutil (in all of its variants): GPLv3+, owned by GNUnet e.V. -* PHP: PHP License, AGPL- and LGPL-Compatible, owned by The PHP Group - -+++++++++++++++++++++++++++ -Bank (git://taler.net/bank) -+++++++++++++++++++++++++++ - ---------- -Licensing ---------- - -This project has been developed by INRIA. For each source file, the -header indicated whose is holding the copyright. The licensing plan -for the bank is to use the Affero GPLv3+. - -Source files of interest are located in the following directories: -(The repository holds also scaffolded files autogenerated by Django, -which do not have legal significance in this context.) - -* TalerBank/Bank/ -* TalerBank/Bank/templates/ -* TalerBank/my-static/ -* website/ - --------------------- -Runtime dependencies --------------------- - -The following list encompasses all the runtime dependencies for this -project, and gives the copyright holder for each of them: - -* Django: BSD License, AGPL-Compatible, owned by Django Software Foundation -* validictory: BSD License, AGPL-Compatible, owned by James Turk -* django-simple-math-captcha: Apache Software License, LGPL-Compatible (FIXME), Brandon Taylor -* requests: Apache2 License, AGPL-Compatible, owned by Kenneth Reitz -* Python: Python Software Foundation License, AGPL-Compatible, Python Software Foundation -* PHP: PHP License, AGPL-Compatible, owned by The PHP Group - - -.. _exchange-repo: - -+++++++++++++++++++++++++++++++++++ -Exchange (git://taler.net/exchange) -+++++++++++++++++++++++++++++++++++ - -This component is based on code initially developed in Munich for -GNUnet e.V. Most recent improvements and maintenance has been done at -Inria. The copyright is thus shared between both institutions. - -The licensing for exported libraries to access the exchange is LGPL, -the exchange itself is under AGPL, and testcases and standalone -binaries are under GPL. - - --------------------- -Runtime dependencies --------------------- - -The following list encompasses all the runtime dependencies for this -project, and gives the copyright holder for each of them: - -* libjansson: MIT License, AGPL- and LGPL-Compatible, owned by Petri Lehtinen and other individuals -* libgcrypt: LGPL, owned by Free Software Foundation -* postgresql: PostgreSQL License, AGPL- and LGPL-Compatible, owned by The PostgreSQL Global Development Group -* libgnunetutil (in all of its variants): GPLv3+, owned by GNUnet e.V. -* libgnunetjson: GPLv3+, GNUnet e.V. - - -+++++++++++++++++++++++++++++++++++++++++ -Web includes (git://taler.net/web-common) -+++++++++++++++++++++++++++++++++++++++++ - -All copyright owned by INRIA (but questionable whether creativity -threshold for copyright is even met). - -Sources are licensed under the GNU LGPL. diff --git a/glossary.rst b/glossary.rst deleted file mode 100644 index d9a6cfa7..00000000 --- a/glossary.rst +++ /dev/null @@ -1,106 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014, 2015, 2016 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 Florian Dold - @author Christian Grothoff - -.. _glossary: - -============== -Taler Glossary -============== - -.. glossary:: - - auditor - trusted third party that verifies that the exchange is operating correctly - - bank - traditional financial service provider who offers wire :term:`transfers ` between accounts - - coin - coins are individual token representing a certain amount of value, also known as the :term:`denomination` of the coin - - contract - specification of the details of a transaction, specifies the payment obligations for the customer (i.e. the amount), the deliverables of the merchant and other related information, such as deadlines or locations - - denomination - unit of currency, specifies both the currency and the face value of a :term:`coin` - - denomination key - RSA key used by the exchange to certify that a given :term:`coin` is valid and of a particular :term:`denomination` - - deposit - operation by which a merchant passes coins to an exchange, expecting the exchange to credit his :term:`bank` account in the future using a wire :term:`transfer` - - dirty - a :term:`coin` is dirty if its public key may be known to an entity other than the customer, thereby creating the danger of some entity being able to link multiple transactions of coin's owner if the coin is not refreshed first - - extension - implementation of a :term:`wallet` for browsers - - fresh coin - a :term:`coin` is fresh if its public key is only known to the customer - - master key - offline key used by the exchange to certify denomination keys and message signing keys - - message signing key - key used by the exchange to sign online messages, other than coins - - owner - a :term:`coin` is owned by the entity that knows the private key of the coin - - proof - message that cryptographically demonstrates that a particular claim is correct - - reserve - funds set aside for future use; either the balance of a customer at the exchange ready for :term:`withdrawal`, or the funds kept in the exchange's bank account to cover obligations from coins in circulation - - refreshing - operation by which a :term:`dirty` :term:`coin` is converted into one or more :fresh: coins - - refund - operation by which a merchant steps back from the right to funds that he obtained from a :term:`deposit` operation, giving the right to the funds back to the customer - - sharing - users can share ownership of a :term:`coin` by sharing access to the coin's private key, thereby allowing all co-owners to spend the coin at any time. - - signing key - see message signing key. - - spending - operation by which a customer gives a merchant the right to :term:`deposit` coins in return for merchandise - - transfer - method of sending funds between :term:`bank` accounts - - transaction - method by which ownership is exclusively transferred from one entity to another - - transaction id - unique number by which a merchant identifies a :term:`transaction` - - wallet - software running on a customer's computer; withdraws, stores and spends coins - - wire transfer - see :term:`transfer` - - wire transfer identifier - subject of a wire :term:`transfer`; usually a random string to uniquely identify the :term:`transfer` - - withdrawal - operation by which a :term:`wallet` can convert funds from a reserve to fresh coins diff --git a/index.rst b/index.rst deleted file mode 100644 index 6de1dbd4..00000000 --- a/index.rst +++ /dev/null @@ -1,124 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014, 2015, 2016 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 - -GNU Taler Documentation -======================= - -We are building an anonymous, taxable payment system using modern -cryptography. Customers will use traditional money transfers to send -money to a digital Exchange and in return receive (anonymized) digital -cash. Customers can use this digital cash to anonymously pay -Merchants. Merchants can redeem the digital cash for traditional -money at the digital Exchange. As Merchants are not anonymous, they can -be taxed, enabling income or sales taxes to be withheld by the state -while providing anonymity for Customers. - -Cryptography is used to ensure that none of the participants can -defraud the others without being detected immediately; however, in -practice a fradulent Exchange might go bankrupt instead of paying the -Merchants and thus the Exchange will need to be audited regularly like -any other banking institution. - -The system will be based on free software and open protocols. - -In this document, we describe the REST-based APIs between the various -components, internal architecture of key components, and how to get them -installed. - ------------------ -Operator Handbook ------------------ - -The *Operator Handbook* is for people who want to run a exchange or a merchant. -It focuses on how to install, configure and run the required software. - -.. toctree:: - :maxdepth: 2 - - global_licensing - configuration-basics - operate-exchange - operate-merchant - versioning - ------------------------- -Web Integration Handbook ------------------------- - -The *Web Integration Handbook* is for those who want to interact with Taler -wallets on their own website. Integrators will also have to be familiar with -the material covered in the *Operator Handbook*. - - -.. toctree:: - :maxdepth: 2 - - integration-general - integration-bank - integration-merchant - example-essay-store - - --------------------------------------- -Taler HTTP 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-bank - - wireformats - - ------------------- -Developer Handbook ------------------- - -The *Developer Handbook* brings developers up to speed who want to hack on the -core components of the Taler reference implementation. - -.. toctree:: - :maxdepth: 2 - - dev-talerdotnet - dev-wallet-wx - dev-exchange - dev-merchant - deployment.rst - releases.rst - ------------------- -Indices and tables ------------------- - -.. toctree:: - :hidden: - - glossary - -* :doc:`glossary` -* :ref:`search` diff --git a/integration-bank.rst b/integration-bank.rst deleted file mode 100644 index 1dc2ec8d..00000000 --- a/integration-bank.rst +++ /dev/null @@ -1,81 +0,0 @@ -============================== -Interaction with bank websites -============================== - -This section describes how bank websites can interact with the -Taler wallet. - -Currently the following functionality is supported: - * Querying for the presence of a Taler wallet. - * Receiving change notifications from the Taler wallet. - * Creating a reserve. - - -For JavaScript code examples, see :ref:`communication`. - -------------------------- -Reserve Creation Request -------------------------- - -The bank website can request the creation of a :term:`reserve`. This operation -will require the user to specify the exchange where he wants to create the reserve -and the resolution of a CAPTCHA, before any action will be taken. - -As a result of the reserve creation request, the following steps will happen in sequence: - 1. The user chooses the desired amount from the bank's form - 2. Upon confirmation, the wallet fetches the desired amount from the user-filled form and - prompts the user for the *exchange base URL*. Then ask the user to confirm creating the - reserve. - 3. The wallet will create a key pair for the reserve. - 4. The wallet will request the CAPTCHA page to the bank. In that request's parameters it - communicates the desired amount, the reserve's public key and the exchange base URL to the - bank - 5. Upon successful resolution of the CAPTCHA by the user, the bank initiates the reserve - creation according to the gotten parameters. Together with `200 OK` status code sent back - to the wallet, it gets also a `ReserveCreated`_ object. - -Note that the reserve creation can be done by a SEPA wire transfer or some other means, -depending on the user's bank and chosen exchange. - -In response to the reserve creation request, the Taler wallet MAY cause the -current document location to be changed, in order to navigate to a -wallet-internal confirmation page. - -The bank requests reserve creation with the ``taler-create-reserve`` event. -The event data must be a `CreateReserveDetail`_: - - -.. _CreateReserveDetail: -.. code-block:: tsref - - interface CreateReserveDetail { - - // JSON 'amount' object. The amount the caller wants to transfer - // to the recipient's count - amount: Amount; - - // CAPTCHA's page URL which needs the following parameters - // query parameters: - // amount_value - // amount_fraction - // amount_currency - // reserve_pub - // exchange - // wire_details (URL encoding of /wire output from the exchange) - callback_url: string; - - // list of wire transfer types supported by the bank - // e.g. "SEPA", "TEST" - wt_types: Array - } - -.. _ReserveCreated: -.. code-block:: tsref - - interface ReserveCreated { - - // A URL informing the user about the succesfull outcome - // of his operation - redirect_url: string; - - } diff --git a/integration-general.rst b/integration-general.rst deleted file mode 100644 index 308ecf5a..00000000 --- a/integration-general.rst +++ /dev/null @@ -1,82 +0,0 @@ -.. _integration-general: - -================================ -Taler Wallet Website Integration -================================ - -.. note:: - The wallet-Websites communication is switching to a new policy which - is NOT based on DOM events, therefore obsoleting this page. To be soon - documented. - - -Websites (such as banks and online shops) can communicate with -the Taler wallet by a standardized protocol. - -From a technical perspective, the Taller wallet communicates with -the website by sending and receiving `DOM events `_ -on the bank website's ``HTMLDocument``. - -DOM events used by Taler have the prefix ``taler-``. - -------------------------- -Wallet Presence Awareness -------------------------- - -The bank website queries the wallet's presence by sending a ``taler-probe`` event. The -event data should be `null`. - -If the wallet is present and active, it will respond with a ``taler-wallet-present`` event. - -While the user agent is displaying a website, the user might deactivate or -re-activate the wallet. A Taler-aware *should* react to those events, and -indicate to the user that they should (re-)enable the wallet if necessary. - -When the wallet is activated, the ``taler-wallet-load`` event is sent -by the wallet. When the wallet is deactivated, the ``taler-wallet-unload`` event -is sent by the wallet. - -.. _communication: - ----------------------- -Communication Example ----------------------- - -The bank website can send the event ``taler-XYZ`` with the event data ``eventData`` -to the wallet with the following JavaScript code: - -.. sourcecode:: javascript - - const myEvent = new CustomEvent("taler-XYZ", eventData); - document.dispatchEvent(myEvent); - -Events can be received by installing a listener: - - -.. sourcecode:: javascript - - function myListener(talerEvent) { - // handle event here! - } - document.addEventListener("taler-XYZ", myListener); - - --------------------- -Normalized Base URLs --------------------- - -Exchanges and merchants have a base URL for their service. This URL *must* be in a -canonical form when it is stored (e.g. in the wallet's database) or transmitted -(e.g. to a bank page). - -1. The URL must be absolute. This implies that the URL has a schema. -2. The path component of the URL must end with a slash. -3. The URL must not contain a fragment or query. - -When a user enters a URL that is, technically, relative (such as "alice.example.com/exchange"), wallets -*may* transform it into a canonical base URL ("http://alice.example.com/exchange/"). Other components *should not* accept -URLs that are not canonical. - -Rationale: Joining non-canonical URLs with relative URLs (e.g. "exchange.example.com" with "reserve/status") -results in different and slightly unexpected behavior in some URL handling libraries. -Canonical URLs give more predictable results with standard URL joining. diff --git a/integration-merchant.rst b/integration-merchant.rst deleted file mode 100644 index f3221617..00000000 --- a/integration-merchant.rst +++ /dev/null @@ -1,315 +0,0 @@ -.. - This file is part of GNU TALER. - -.. - Note that this page is more a protocol-explaination than a guide that teaches - merchants how to work with Taler wallets - - Copyright (C) 2014, 2015, 2016 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 - @author Christian Grothoff - -================================== -Interaction with merchant websites -================================== - -.. _payprot: - -+++++++++++++++++++ -The payment process -+++++++++++++++++++ - -By design, the Taler payment process ensures the following properties: - -1. The user must see and accept a contract in a secure context before the payment happens. - That contract accounts for all the items which are supposed to be bought. - -2. The payment process must be idempotent, that is at any later time the customer must - be able to replay the payment and retrieve the resource he paid for. - In case where a physical item was bought, this online resource is the merchant's - order status page, which may contain tracking information for the customer. - Note that by `replaying the payment` we mean reusing the `same coins` used to pay for - the product the first time to get the `same product` the user got the first time. - So the replay does NOT subtract further credit from the user's total budget. - -3. Purchases are shareable: any purchase is given a URL that allows other users to - buy the same item(s). - -We call an *offer URL* any URL at the merchant's Web site that notifies the -wallet that the user needs to pay for something. The offer URL must take into -account that the user has no wallet installed, and manage the situation accordingly -(for example, by showing a credit card paywall). The notification can happen either -via JavaScript or via HTTP headers. - -The merchant needs to have a *contract URL* which generates the JSON -contract for Taler. Alternatively, the contract may be embedded -within the page returned by the offer URL and given to the wallet -via JavaScript or via an HTTP header. - -The merchant must also provide a *pay URL* to which the wallet can -transmit the payment. Again, how this URL is made known from the merchant -to the wallet, it is managed by the HTTP headers- or JavaScript-based protocol. - -The merchant must also have a *fulfillment URL*, that addresses points 2 and 3 above. -In particular, fulfillment URL is responsible for: - -* Deliver the final product to the user after the payment -* Instruct the wallet to send the payment to the pay URL -* Redirect the user to the offer URL in case they hit a shared fulfillment URL. - -Again, Taler provides two ways of doing that: JavaScript- and HTTP headers-based. - -Taler helps merchants on the JavaScript-based interaction by providing the -``taler-wallet-lib``. See https://git.taler.net/web-common.git/tree/taler-wallet-lib.ts - -------- -Example -------- - -For example, suppose Alice wants to pay for a movie. She will first -select the movie from the catalog, which directs her to the offer URL -*https://merchant/offer?x=8ru42*. This URL generates a "402 Payment -Required" response, and will instruct the wallet about the contract's -URL. Then the wallet downloads the contract that states that Alice is -about to buy a movie. The contract includes a fresh transaction ID, say 62. -Alice's browser detects the response code and displays the contract -for Alice. - -Alice then confirms that she wants to buy the movie. Her wallet -associates her confirmation with the details and a hash of the contract. -After Alice confirms, the wallet redirects her to the fulfillment URL, say -*https://merchant/fulfillment?x=8ru42&tid=62* that is specified in the -contract. - -The first time Alice visits this URL, the merchant will again -generate a "402 Payment Required" response, this time not including -the full contract but merely the hash of the contract (which includes -Alice's transaction ID 62), as well as the offer URL (which Alice -will ignore) and the pay URL. Alice's wallet will detect that -Alice already confirmed that she wants to execute this particular -contract. The wallet will then transmit the payment to the pay URL, -obtain a response from the merchant confirming that the payment was -successful, and then reload the fulfillment URL. - -This time (and every time in the future where Alice visits the -fulfillment URL), she receives the movie. If the browser has lost the -session state, the merchant will again ask her to pay (as it happened the -very first time she visited the fulfillment URL), and she will authenticate -by replaying the payment. - -If Alice decides to share the fulfillment URL with Bob and he visits -it, his browser will not have the right session state and furthermore -his wallet will not be able to replay the payment. Instead, his wallet -will automatically redirect Bob to the offer URL and allow him to -purchase the movie himself. - -.. _offer: - ---------------- -Making an offer ---------------- - -When a user visits a offer URL, the merchant returns a page that can interact -with the wallet either via JavaScript or by returning a "402 Payment Required". -This page's main objective is to inform the wallet on where it should get the -contract. In case of JavaScript interaction, the merchant should just return -a page whose javascript contains an invocation to ``offerContractFrom()`` -from ``taler-wallet-lib``. This function will download the contract from -`` and hand it to the wallet. - -In case of HTTP headers-based protocol, the merchant needs to set the header -`X-Taler-contract-url` to the contract URL. Once this information reaches the -browser, the wallet will takes action by reading that header and downloading -the contract. - -Either way, the contract gets to the wallet which then renders it to the user. - -.. _fulfillment: - -------------------------------- -Fulfillment interaction details -------------------------------- - -A payment process is triggered whenever the user visits a fulfillment -URL and he has no rights in the session state to get the items -accounted in the fulfillment URL. Note that after the user accepts a -contract, the wallet will automatically point the browser to the -fulfillment URL. - -Becasue fulfillment URLs implements replayable and shareable payments -(see points 2,3 above), fulfillment URL parameter must encompass all the -details necessary to reconstruct a contract. - -That saves the merchant from writing contracts to disk upon every contract -generation, and defer this operation until customers actually pay. - -.................. -HTTP headers based -.................. - -Once the fulfillment URL gets visited, deliver the final product if the user has -paid, otherwise: the merchant will reconstruct the contract and re-hash it, sending -back to the client a "402 Payment required" status code and some HTTP headers which -will help the wallet to manage the payment. Namely: - -* `X-taler-contract-hash` -* `X-taler-pay-URL` -* `X-taler-offer-URL` - -The wallet then looks at `X-taler-contract-hash`, and can face two situations: - -1. This hashcode is already present in the wallet's database (meaning that the user did accept the related contract), so the wallet can send the payment to `X-taler-pay-URL`. During this operation, the wallet associates the coins it sent to `X-taler-pay-URL` with this hashcode, so that it can replay payments whenever it gets this hashcode again. - -2. This hashcode is unknown to the wallet (meaning that the user visited a shared fulfillment URL). The wallet then points the browser to `X-taler-offer-URL`, which is in charge of generating a contract referring to the same items accounted in the fulfillment URL. Of course, the user is then able to accept or not the contract. - -................ -JavaScript based -................ - -Once the fulfillment URL gets visited, deliver the final product if the user has paid, otherwise: -the merchant will reconstruct the contract and re-hash it. Then it will return a page whose JavaScript -needs to include a call to ``taler.executeContract(..)``. See the following example: - -.. sourcecode:: html - - - - - - - .. - - - -The logic which will take place is the same as in the HTTP header based protocol. -Once ``executePayment(..)`` gets executed in the browser, it will hand its three -parameters to the wallet, which will: - -1. Send the payment to `` if `` is found in its database (meaning that the user accepted it). -2. Redirect the browser to ``, if `` is NOT found in its database, meaning that the user visited a shared fulfillment URL. - --------------------- -Example: Essay Store --------------------- - -This section is a high-level description of a merchant :ref:`frontend `, -and is inspired by our demonstration essay store running at `https://blog.demo.taler.net/`. -Basically, it tells how the frontend reacts to clients visiting `offer` and `fulfillment` -URLs. - -The website is implemented in Python+Flask, and is available at -https://git.taler.net/merchant-frontends.git/tree/talerfrontends/blog. - -The desired effect is that the homepage has a list of buyable articles, and once the -user clicks on one of them, they will either get the Taler :ref:`contract ` -or a credit card paywall if they have no Taler wallet installed. - -In particular, any buyable article on the homepage links to an `offer URL`: - -.. sourcecode:: html - - - ... -

How to write a frontend

- ... - - -whence the offer URL design is as follows:: - - https:///essay/ - -`` is just a token that uniquely identifies the article within the shop. - -The server-side handler for the offer URL will return a special page to the client that -will either HTTP GET the contract from the frontend, or show the credit card paywall. -See `above `_ how this special page works. - -It is interesting to note that the fulfillment URL is just the offer URL plus -two additional parameters. It looks as follows:: - - https:///essay/?tid=×tamp= - -.. note:: - - Taler does not require that offer and fulfillment URL have this kind of relationship. - In fact, it is perfectly acceptable for the fulfillment URL to be hosted on a different - server under a different domain name. - -The fulfillment URL server-side handler implements the following logic: it checks the state -to see if `` has been payed, and if so, returns the article to the user. -If the user didn't pay, then it `executes` the contract by returning a special page to the -browser. The contract execution is the order to pay that the frontend gives to the wallet. - -Basically, the frontend points the wallet to the hashcode of the contract which is to be paid -and the wallet responds by giving coins to the frontend. Because the frontend doesn't perform -any cryptographic work by design, it forwards ``, `` and -`` to the frontend in order to get the contract's hashcode. - -See `above `_ for a detailed description of how the frontend triggers the -payment in the wallet. - -.................. -State and security -.................. - -The server-side state gets updated in two situations, (1) when an article is -"about" to be bought, which means when the user visits the fulfillment URL, -and (2) when the user actually pays. For (1), we use the contract hascode to -access the state, whereas in (2) we just define a list of payed articles. -For example: - -.. sourcecode:: python - - session[] = {'article_name': 'How_to_write_a_frontend'} # (1) - session['payed_articles'] = ['How_to_write_a_frontend', 'How_to_install_a_backend'] # (2) - -The list of payed articles is used by the frontend to deliver the article to the user: -if the article name is among ``session['payed_articles']``, then the user gets what they -paid for. - -The reason for using `` as the key is to prevent the wallet to send bogus -parameters along the fulfillment URL. `` is the contract hashcode that -the fulfillment handler gets from the backend using the fulfillment URL parameters. - -In fact, when the wallet sends the payment to the frontend pay handler, it has to provide -both coins and contract hashcode. That hascode is (1) verified by the backend when it -receives the coins, (2) used by the frontend to update the list of payed articles. - -See below an example of pay handler: - -.. sourcecode:: python - - ... - - # 'deposit_permission' is the JSON object sent by the wallet - # which contains coins and the contract hashcode. - response = send_payment_to_backend(deposit_permission) - - # The backend accepted the payment - if 200 == response.status_code: - # Here we pick the article name from the state defined at - # fulfillment time. - # deposit_permission['H_contract'] is the contract hashcode - payed_article = session[deposit_permission['H_contract']]['article_name'] - session['payed_articles'].append(payed_article) - - -So the wallet is forced to send a valid contract hashcode along the payment, -and since that hashcode is then used to update the list of payed articles, -the wallet is forced to send fulfillment URL parameters that match that hashcode, -therefore being valid parameters. diff --git a/operate-exchange.rst b/operate-exchange.rst deleted file mode 100644 index 874b837c..00000000 --- a/operate-exchange.rst +++ /dev/null @@ -1,246 +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 - -====================== -Operating the Exchange -====================== - -+++++++++++++ -Configuration -+++++++++++++ - -The following data and facilities have to be set up, in order to run an exchange: - -* Keying -* Serving -* Currency -* Bank account -* Coins -* Database - -In this document, we assume that ``$HOME/.config/taler.conf`` is being customized. - ------- -Keying ------- - -The exchange works with three types of keys: - -* `master key` -* `sign keys` -* `denomination keys` (see section `Coins`) - -`master key`: in section `[exchange]`, edit the two following values: - -* `master_priv_file`: Path to the exchange's master private file. -* `master_public_key`: Must specify the exchange's master public key. - -`sign keys`: the following two options under `[exchange_keys]` section control `sign keys`: - -* `signkey_duration`: How long should one signing key be used? -* `lookahead_sign`: How much time we want to cover with our `signkeys`? Note that if `signkey_duration` is bigger than `lookahead_sign`, `taler-exchange-keyup` will generate a quantity of `signkeys` which is sufficient to cover all the gap. See :ref:`keys-duration`. - -------- -Serving -------- - -The exchange can serve HTTP over both TCP and UNIX domain socket. It needs this -configuration *twice*, because it opens one connection for ordinary REST calls, and one -for "/admin" and "/test" REST calls, because the operator may want to restrict the access to "/admin". - -The following values are to be configured under the section `[exchange]` and `[exchange-admin]`: - -* `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----). - -The exchange can be started with the `-D` option to disable the administrative -functions entirely. It is recommended that the administrative API is only -accessible via a properly protected UNIX domain socket. - --------- -Currency --------- - -The exchange supports only one currency. This data is set under the respective -option `currency` in section `[taler]`. - ------------- -Bank account ------------- - -Wireformat -^^^^^^^^^^ - -The wireformat is the protocol to be used between the exchange and the banks. -The option is `wireformat`, under section `[exchange]`. The exchange currently supports -the `test` wireformat. This wireformat is used for testing the system against a fictional bank. - -.. note:: - The SEPA wireformat is work in progress. - -Incoming -^^^^^^^^ -The bank account where the exchange gets money from customers is configured under -the section `[exchange-wire-incoming-X]`, where `X` matches the value given to the -option `wireformat`. This section contains only one option: `X_response_file`, which -takes the path to a text file containing the exchange's bank account details in JSON -format. - -The command line tool `taler-exchange-wire` is used to create such a file. -For example, the utility may be invoked as follows:: - - $ taler-exchange-wire -j '{"name": "The Exchange", "account_number": 10, "bank_uri": "https://bank.demo.taler.net", "type": "test"}' -t test -o exchange.json - -Note that the value given to option `-t` must match the value in the JSON's field ``"type"``. - -The generated file will be echoed by the exchange when serving :ref:`/wire ` requests. - -Outgoing -^^^^^^^^ - -This exchange's bank account is used to give money to merchants, after successful :ref:`deposits ` -operations. If `test` is the chosen wireformat, the outcoming bank account is configured by the following -options under `[exchange-wire-outcoming-test]`: - - * `exchange_account_numer`: which bank account number has the exchange - * `bank_uri`: base URL of the bank hosting the exchange bank account - -.. note:: - The rationale behind having two 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. - --------- -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 `db_conn_str`, under section `[exchangedb-BACKEND]`. For example, the demo exchange is configured as follows: - -.. code-block:: text - - [exchange] - ... - db = postgres - ... - - [exchangedb-postgres] - db_conn_str = postgres:///talerdemo - -------------------------- -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 -------------- - -Both `signkeys` and `denom keys` have a :ref:`starting date `. The option `lookahead_provide`, under section `[exchange_keys]`, is such that only keys -whose starting date is younger than `lookahead_provide` will be issued by the exchange. - -.. _exchange-install: - -++++++++++++ -Installation -++++++++++++ - -Please install the following packages before proceeding with the exchange compilation. - -* 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 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://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``. - -To download and install the GNU Taler exchange, proceeds 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. - -+++++ -Other -+++++ - ------------------- -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. diff --git a/operate-merchant.rst b/operate-merchant.rst deleted file mode 100644 index 484d6eba..00000000 --- a/operate-merchant.rst +++ /dev/null @@ -1,212 +0,0 @@ -.. - This file is part of GNU TALER. - Copyright (C) 2014, 2015, 2016 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 - @author Florian Dold - -============================== -Operating the Merchant Backend -============================== - -+++++++++++++ -Configuration -+++++++++++++ - -The following data and facilities have to be set up, in order to run a merchant backend: - -* Serving -* Currency -* Database -* Exchanges -* Keying -* Bank account -* Instances - -In this document, we assume that ``$HOME/.config/taler.conf`` is being customized. - -------- -Serving -------- - -The merchant backend can serve HTTP over both TCP and UNIX domain socket. - -The following values are to be configured under the section `[merchant]`: - -* `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 --------- - -The merchant backend supports only one currency. This data is set under the respective -option `currency` in section `[taler]`. - --------- -Database --------- - -The option `db` under section `[merchant]` gets the DB backend's name the merchant -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_MERCHANTDB_POSTGRES_CONFIG`. -* via configuration option `config`, under section `[merchantdb-BACKEND]`. For example, the demo merchant is configured as follows: - -.. code-block:: text - - [merchant] - ... - db = postgres - ... - - [merchantdb-postgres] - config = postgres:///talerdemo - ---------- -Exchanges ---------- - -The options `uri` and `master_key`, under section `[merchant-exchange-MYEXCHANGE]`, let -the merchant add the exchange `MYEXCHANGE` among the exchanges the merchant wants to work -with. `MYEXCHAGE` is just a mnemonic name chosen by the merchant (which is not currently used -in any computation), and the merchant can add as many exchanges as it is needed. -`uri` is the exchange's base URL. Please note that a valid `uri` complies with the following -pattern:: - - schema://hostname/ - -`master_key` is the base32 encoding of the exchange's master key (see :ref:`/keys `). -In our demo, we use the following configuration:: - - [merchant-exchange-test] - URI = https://exchange.test.taler.net/ - MASTER_KEY = CQQZ9DY3MZ1ARMN5K1VKDETS04Y2QCKMMCFHZSWJWWVN82BTTH00 - ------- -Keying ------- - -The option `keyfile` under section `[merchant-instance-default]` is the path to the -merchant's :ref:`default instance ` private key. This key is needed to -sign certificates and other messages sent to wallets and exchanges. -To generate a 100% compatible key, it is recommended to use the ``gnunet-ecc`` tool. - ------------- -Bank account ------------- - -This piece of information is used when the merchant redeems coins to the exchange. -That way, the exchange will know to which bank account it has to transfer real money. -The merchant must specify which system it wants receive wire transfers with. We support -a `test` wire format so far, and supporting `SEPA` is among our priorities. - -The wire format is specified in the option `wireformat` under section `[merchant]`, -and the wire details are given via a JSON file, whose path must be indicated in the -option `X_response_file` under section `[default-wireformat]`, where `X` matches -the chosen wireformat. In our demo, we have:: - - [merchant] - .. - wireformat = test - .. - - [merchant-instance-wireformat-default] - test_response_file = ${TALER_CONFIG_HOME}/merchant/wire/test.json - -The file `test.json` obeys to the following specification - -.. code-block:: tsref - - interface WireDetails { - // matches wireformat - type: string; - - // base URL of the merchant's bank - bank_uri: string; - - // merchant's signature (unused, can be any value) - signature: string; - - // merchant's account number at the bank - account_number: Integer; - - // the salt (unused, can be any value) - salt: any; - } - -As an example, `test.json` used in our demo is shown below:: - - { - "type": "test", - "bank_uri": "https://bank.test.taler.net/", - "sig": "MERCHANTSIGNATURE", - "account_number": 6, - "salt": "SALT" - } - - - -.. _instances-lab: - ---------- -Instances ---------- - -In Taler, multiple shops can rely on the same :ref:`merchant backend `. -In Taler terminology, each of those shops is called `(merchant) instance`. Any instance -is defined by its private key and its wire details. In order to add the instance `X` to -the merchant backend, we have to add the sections `[merchant-instance-X]` and `[X-wireformat]`, -and edit them as we did for the `default` instance. For example, in our demo we add the -instance `Tor` as follows:: - - [merchant-instance-Tor] - KEYFILE = ${TALER_DATA_HOME}/merchant/tor.priv - - .. - - [merchant-instance-wireformat-Tor] - TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/merchant/wire/tor.json - -Please note that :ref:`Taler messagging` is designed so that the merchant -frontend can instruct the backend on which instance has to be used in the various operations. -This information is optional, and if not given, the backend will act as the `default` instance. - -++++++++++++ -Installation -++++++++++++ - - - - - -In order to compile your merchant backend, you firstly need to install the GNU Taler -exchange. As of other dependencies, the merchant backend needs exactly the same ones -as the exchange does. Follow :ref:`those instructions ` to build -everything needed. - -Assuming all the dependencies have been correctly installed, we can now build the -merchant backend using the following commands:: - - $ 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 diff --git a/wireformats.rst b/wireformats.rst deleted file mode 100644 index 4e154930..00000000 --- a/wireformats.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. _wireformats: - -Wire Transfer Formats -===================== - -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 type of wire transfer -used. Since the wire transfers differ for each region, we document here the -ones currently supported by the exchange. - -TEST ----- - -The TEST 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 TEST -wire format in combination with the Taler's bank, it is thus possible to -fully test the Taler system without using "real" currencies. The wire -format for "TEST" is very simple, in that it only specifies an account -number in a field "account_number" and the URI of the bank: - - * `type`: the string constant `"test"` - * `bank_uri`: the URI of the bank (starting with `http://` or `https://`) - * `account_number`: the number of the account at the bank - -The account number given must be a positive 53-bit integer. -Additional fields may be present, but are not required. - -Note that a particular exchange is usually only supporting one -particular bank with the "TEST" wire format, so it is not possible for -a merchant with an account at a different bank to use "TEST" to -transfer funds across banks. After all, this is for testing and not -for real banking. - -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 *EURO*. 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 -contain a JSON object with the following fields: - - .. The following are taken from Page 33, SEPA_SCT.pdf . - - * `type`: the string constant `"sepa"` - * `iban`: the International Bank Account Number (IBAN) of the account of the beneficiary - * `name`: the name of the beneficiary - * `bic`: the Bank Identification Code (BIC) code of the beneficiary's bank - * `salt`: random salt (used to make brute-forcing the hash harder) - -The JSON object may optionally contain: - * `address`: the address of the Beneficiary - -The implementation of the SEPA plugin 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