taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

commit b6af341199612298e08e51936376d65e44f71ef6
parent f39296194956d83fb77a5cc0db3c747d11b72eef
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu, 26 Nov 2015 13:35:21 +0100

Merge branch 'master' of git.taler.net:api

Diffstat:
Mapi-merchant.rst | 58++++++++++++++++++++++++++--------------------------------
Mapi-mint.rst | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Abanks.rst | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mindex.rst | 1+
4 files changed, 294 insertions(+), 42 deletions(-)

diff --git a/api-merchant.rst b/api-merchant.rst @@ -53,8 +53,13 @@ may want to make the Taler payment option visible `only if` the user has the Tal wallet active in his browser. So the notification is mutual: * the website notifies the wallet (`s -> w`), so it can change its color -* the wallet notifies the website (`w -> s`), so it can show Taler as a - suitable payment option +* the wallet notifies the website (`w -> s`) by modifing the page's DOM, so + it can show Taler as a suitable payment option + +We acknowledge that notifying the website leaks the fact that Taler is installed, +which could help track or deanonymize users. We believe the usability gained by +leaking this one bit represents an acceptable trade off. It would rapidly become +problematic though if several payment options take this approach. Furthermore, there are two scenarios according to which the mutual signaling would succeed. For a page where the merchant wants to show a Taler-style payment @@ -62,9 +67,8 @@ option and, accordingly, the wallet is supposed to change its color, there are two scenarios we need to handle: * the customer has the wallet extension active at the moment of visiting the page, or -* the customer activates the wallet extension - (regardless of whether he installs it or simply enables it) - `after` downloading the page. +* the customer activates the wallet extension `after` downloading the page, + regardless of whether he installs it or simply enables it. In the first case, the messaging sequence is `s -> w` and `w -> s`. In the second case, the first attempt (`s -> w`) will get no reply; however, as soon as the @@ -95,11 +99,11 @@ using coins in the form of a `deposit permission`. This signature using the coins signifies both agreement of the customer and represents payment at the same time. The `frontend` passes the `deposit permission` to the `backend` which immediately verifies it -with the mint and signals the `frontend` the success (or failure) of +with the mint and signals the `frontend` the success or failure of the payment process. If the payment is successful, the `frontend` is responsible for generating the fullfillment page. -The contract format is specified in section `contract`_. +The contract format is specified in the `contract`_ section. +++++++++ @@ -141,11 +145,13 @@ successful response to the following two calls: :>json object merchant: the set of values describing this `merchant`, defined below :>json base32 H_wire: the hash of the merchant's :ref:`wire details <wireformats>`; this information is typically added by the `backend` :>json base32 H_contract: encoding of the `h_contract` field of contract :ref:`blob <contract-blob>`. Tough the wallet gets all required information to regenerate this hash code locally, the merchant sends it anyway to avoid subtle encoding errors, or to allow the wallet to double check its locally generated copy - :>json array auditors: a JSON array of `auditor` objects. To finalize the payment, the wallet should agree on a mint audited by one of these auditos. + :>json array auditors: a JSON array of `auditor` objects. Any mints audited by these auditors are accepted by the merchant. :>json string pay_url: the URL where the merchant will receive the deposit permission (i.e. the payment) - :>json array mints: a JSON array of `mint` objects. The wallet is encouraged to agree on some of those mints, in case it can't agree on any auditor trusted by this merchant. + :>json array mints: a JSON array of `mint` objects that the merchant accepts even if it does not accept any auditors that audit them. :>json object locations: maps labels for locations to detailed geographical location data (details for the format of locations are specified below). The label strings must not contain a colon (`:`). These locations can then be references by their respective labels throughout the contract. + The wallet must select a mint that either the mechant accepts directly by listing it in the mints arry, or for which the merchant accepts an auditor that audits that mint by listing it in the auditors array. + The `product` object focuses on the product being purchased from the merchant. It has the following structure: :>json string description: this object contains a human-readable description of the product @@ -227,15 +233,15 @@ The HTML page implements all interactions using JavaScript signals dispatched on the HTML element `body`. When the merchant wants to notify the availability of a Taler-style payment -option (for example on a "checkout" page), it sends the following event: +option, such as on a "checkout" page, it sends the following event: .. js:data:: taler-checkout-probe This event must be sent from a callback for the `onload` event of the `body` element, otherwise the extension would have not time to register a listener for this event. It also needs to be sent when -the Taler extension is dynamically loaded (if the user activates -the extension while he is on the checkout page). This is done by +the Taler extension is dynamically loaded, like when the user activates +the extension while he is on the checkout page. This is done by listening for the .. js:data:: taler-load @@ -250,25 +256,13 @@ for example by updating the DOM to enable the respective button. The following events are needed when one of the two parties leaves the scenario. -First, if the Taler extension is unloaded while the user is +If the Taler extension is unloaded while the user is visiting a checkout page, the page should listen for the .. js:data:: taler-unload event to hide the Taler payment option. -Secondly, when the Taler extension is active and the user closes (or navigates -away from) the checkout page, the page should listen to a - - .. js:data:: taler-navigating-away - -event, and reply with a - - .. js:data:: taler-checkout-away - -event, in order to notify the extension that the user is leaving a checkout -page, so that the extension can change its color back to its default. - The following source code highlights the key steps for adding the Taler signaling to a checkout page: @@ -397,6 +391,8 @@ cookies to identify the shopping session. :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. +.. _deposit-permission: + .. http:post:: /taler/pay Send the deposit permission to the merchant. Note that the URL may differ between @@ -404,7 +400,7 @@ cookies to identify the shopping session. :reqheader Content-Type: application/json :<json base32 H_wire: the hashed :ref:`wire details <wireformats>` of this merchant. The wallet takes this value as-is from the contract - :<json base32 H_contract: the base32 encoding of the field `h_contract` of the contract `blob <contract-blob>`. The wallet can choose whether to take this value from the gotten contract (field `h_contract`), or regenerating one starting from the values it gets within the contract + :<json base32 H_contract: the base32 encoding of the field `h_contract` of the contract `blob <contract-blob>`. 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 :<json int transaction_id: a 53-bit number corresponding to the contract being agreed on :<json date timestamp: a timestamp of this deposit permission. It equals just the contract's timestamp :<json date refund_deadline: same value held in the contract's `refund` field @@ -421,10 +417,7 @@ cookies to identify the shopping session. **Success Response:** - :status 200 OK: the payment has been received. - :resheader Content-Type: text/html - - In this case the merchant sends back a `fullfillment` page in HTML, which the wallet will make the new `body` of the merchant's current page. It is just a confirmation of the positive transaction's conclusion. + :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:** @@ -471,7 +464,7 @@ The following API are made available by the merchant's `backend` to the merchant :reqheader Content-Type: application/json - The `frontend` passes the deposit permission received from the wallet, by adding the field `max_fee` (see `contract`) and optionally adding a field named `edate`, indicating a deadline by which he would expect to receive the bank transfer for this deal + The `frontend` passes the :ref:`deposit permission <deposit-permission>` received from the wallet, by adding the fields `max_fee`, `amount` (see :ref:`contract`) and optionally adding a field named `edate`, indicating a deadline by which he would expect to receive the bank transfer for this deal **Success Response: OK** @@ -479,4 +472,5 @@ The following API are made available by the merchant's `backend` to the merchant **Failure Responses:** - The `backend` will return error codes received from the mint verbatim (see `/deposit` documentation for the mint API for possible errors). If the wallet made a mistake (for example, by double-spending), the `frontend` should pass the reply verbatim to the browser/wallet. (This is pretty much always the 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.) + The `backend` will return verbatim the error codes received from the mint's :ref:`deposit <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. + diff --git a/api-mint.rst b/api-mint.rst @@ -32,9 +32,9 @@ This section describes how certain types of values are represented throughout th .. _Signature: - * **Signatures**: The specific signature scheme in use, like RSA blind signatures or EdDSA, depends on the context. RSA blind signatures are only used for coins and always simply base32_ encoded. + * **Signatures**: The specific signature scheme in use, like RSA blind signatures or EdDSA, depends on the context. RSA blind signatures are only used for coins and always simply base32_ encoded. -EdDSA signatures are transmitted as 64-byte base32_ binary-encoded objects with just the R and S values (base32_ binary-only). +EdDSA signatures are transmitted as 64-byte base32_ binary-encoded objects with just the R and S values (base32_ binary-only). These signed objects always contain a purpose number unique to the context in which the signature is used, but frequently the actual binary-object must be reconstructed locally from information available only in context, such as recent messages or account detals. These objects are described in detail in :ref:`Signatures`. @@ -235,7 +235,8 @@ When transfering money to the mint such as via SEPA transfers, the mint creates :>jsonarr string type: either the string "WITHDRAW" or the string "DEPOSIT" :>jsonarr object amount: the amount_ that was withdrawn or deposited :>jsonarr object wire: a JSON object with the wiring details needed by the banking system in use, present in case the `type` was "DEPOSIT" - :>jsonarr object signature: signature_ (full object with all details) made with purpose `TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW` made with the reserve's public key over the original "WITHDRAW" request, present if the `type` was "WITHDRAW" + :>jsonarr string details: base32_ binary encoding of the transaction data as a `TALER_WithdrawRequestPS` struct described in :ref:`Signatures`, only present if the `type` was "WITHDRAW". Its `purpose` should match our `type`, `amount_with_fee`, should match our `amount`, and its `size` should be consistent. + :>jsonarr object signature: the EdDSA signature_ (binary-only) made with purpose `TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW` over the transaction's details, again only present if the `type` was "WITHDRAW". **Error Response: Unknown reserve** @@ -332,7 +333,8 @@ Deposit operations are requested by a merchant during a transaction. For the dep :>jsonarr string type: either "deposit" or "melt" :>jsonarr object amount: the total amount_ of the coin's value absorbed by this transaction - :>jsonarr object signature: the signature_ (JSON object) of purpose `TALER_SIGNATURE_WALLET_COIN_DEPOSIT` or `TALER_SIGNATURE_WALLET_COIN_MELT` with the details of the transaction that drained the coin's value + :>jsonarr string details: base32_ binary encoding of the transaction data as a `TALER_DepositRequestPS` or `TALER_RefreshMeltCoinAffirmationPS` struct described in :ref:`Signatures`. Its `purpose` should match our `type`, `amount_with_fee`, should match our `amount`, and its `size` should be consistent. + :>jsonarr object signature: the EdDSA signature_ (binary-only) made with purpose `TALER_SIGNATURE_WALLET_COIN_DEPOSIT` or `TALER_SIGNATURE_WALLET_COIN_MELT` over the transaction's details. **Error Response: Invalid signature**: @@ -394,9 +396,9 @@ However, the new coins are linkable from the private keys of all old coins using :status 200 OK: The request was succesful. The response body contains a JSON object with the following fields: :resheader Content-Type: application/json - :<json int noreveal_index: Which of the `kappa` indices does the client not have to reveal. - :<json base32 mint_sig: binary-only Signature_ for purpose `TALER_SIGNATURE_MINT_CONFIRM_MELT` whereby the mint affirms the successful melt and confirming the `noreveal_index` - :<json base32 mint_pub: public EdDSA key of the mint that was used to generate the signature. Should match one of the mint'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. + :>json int noreveal_index: Which of the `kappa` indices does the client not have to reveal. + :>json base32 mint_sig: binary-only Signature_ for purpose `TALER_SIGNATURE_MINT_CONFIRM_MELT` whereby the mint affirms the successful melt and confirming the `noreveal_index` + :>json base32 mint_pub: public EdDSA key of the mint that was used to generate the signature. Should match one of the mint'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. **Error Response: Invalid signature**: @@ -488,9 +490,123 @@ However, the new coins are linkable from the private keys of all old coins using :>json string parameter: will be "coin_pub" --------------------- + +----------------------- +Tracking wire transfers +----------------------- + +This API is used by merchants that need to find out which wire +transfers (from the mint 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.) + + .. note:: + + Wire transfer tracking is currently not implemented (#3888). + + +.. http:get:: /wire/deposits + + Provides deposits associated with a given wire transfer. + :query wtid: wire transfer identifier identifying the wire transfer (a base32-encoded value) + + **Success Response: OK** + + :status 200 OK: The wire transfer is known to the mint, details about it follow in the body. + :resheader Content-Type: application/json + :>json object total: Total amount_ transferred. + :>json base32 H_wire: hash of the wire details (identical for all deposits) + :>json base32 merchant_pub: public key of the merchant (identical for all deposits) + :>json object deposits: JSON array with **deposit details**. + + Objects in the deposit array have the following format: + + :>jsonarr object f: the amount_ of the original deposit amount + :>jsonarr object deposit_fee: applicable fees for the deposit + :>json base32 H_contract: SHA-512 hash of the contact of the merchant with the customer. Further details are never disclosed to the mint. + :>json base32 coin_pub: coin's public key, both ECDHE and EdDSA. + :>json date timestamp: timestamp when the contract was finalized, must match approximately the current time of the mint + :>json int transaction_id: 64-bit transaction id for the transaction between merchant and customer + :>json date refund_deadline: date until which the merchant can issue a refund to the customer via the mint, possibly zero if refunds are not allowed. + :>json base32 coin_sig: the EdDSA signature_ (binary-only) made with purpose `TALER_SIGNATURE_WALLET_COIN_DEPOSIT` made by the customer with the coin's private key. + + + **Error Response: Unknown wire transfer identifier** + + :status 404 Not Found: The wire transfer identifier is unknown to the mint. + :resheader Content-Type: application/json + :>json string error: the value is always "Wire transfer identifier not found" + :>json string parameter: the value is always "wtid" + + +.. http:get:: /deposit/wtid + + Provide the wire transfer identifier associated with an (existing) deposit operation. + + :reqheader Content-Type: application/json + :<json base32 H_wire: SHA-512 hash of the merchant's payment details. + :<json base32 H_contract: SHA-512 hash of the contact of the merchant with the customer. + :<json base32 coin_pub: coin's public key, both ECDHE and EdDSA. + :<json int transaction_id: 64-bit transaction id for the transaction between merchant and customer + :<json base32 merchant_pub: the EdDSA public key of the merchant, so that the client can identify the merchant for refund requests. + :<json base32 merchant_sig: the EdDSA signature of the merchant made with purpose `TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID` , affirming that it is really the merchant who requires obtaining the wire transfer identifier. + + **Success Response: OK** + + :status 200 OK: The deposit has been executed by the mint and we have a wire transfer identifier. + :resheader Content-Type: application/json + :>json base32 wtid: wire transfer identifier of the deposit. + :>json date execution_time: when was the wire transfer given to the bank. + :>json base32 mint_sig: binary-only Signature_ for purpose `TALER_SIGNATURE_MINT_CONFIRM_WIRE` whereby the mint affirms the successful wire transfer. + :>json base32 mint_pub: public EdDSA key of the mint that was used to generate the signature. Should match one of the mint'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. + + **Error Response: Wire transfer not yet executed** + + :status 202 Accepted: The deposit request has been accepted for processing, but was not yet executed. Hence the mint does not yet have a wire transfer identifier. The merchant should come back later and ask again. + :resheader Content-Type: application/json + :>json date execution_time: time by which the mint currently thinks the deposit will be executed. + + **Error Response: Invalid signature**: + + :status 401 Unauthorized: The signature is invalid. + :resheader Content-Type: application/json + :>json string error: the value is "invalid signature" + :>json string paramter: the value is "merchant_sig" + + **Error Response: Unknown wire transfer identifier** + + :status 404 Not Found: The deposit operation is unknown to the mint + :resheader Content-Type: application/json + :>json string error: the value is always "Deposit unknown" + + + + + +------- Refunds --------------------- +------- .. note:: @@ -535,6 +651,7 @@ interception. :>json object sign_info: Public part of the signing key :>json base32 sign_priv: Private EdDSA key +.. _add-incoming: ------------------------------------- Administrative API: Bank transactions @@ -602,7 +719,6 @@ Administrative API: Bank transactions :>json string error: the error message (`permission denied`) :>json string hint: hint as to why permission was denied - ------------ The Test API ------------ @@ -958,3 +1074,13 @@ The `size` field of the corresponding `struct SignedData` is determined by the s struct GNUNET_HashCode h_wire_types; } }; + + struct TALER_DepositTrackPS { + signed (purpose = TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID) { + struct GNUNET_HashCode h_contract; + struct GNUNET_HashCode h_wire; + uint64_t transaction_id; + struct TALER_MerchantPublicKeyP merchant; + struct TALER_CoinSpendPublicKeyP coin_pub; + } + }; diff --git a/banks.rst b/banks.rst @@ -0,0 +1,131 @@ +=================================== +Interaction with banks Web portals +=================================== + +This section describes the interactions that should occur between +a wallet and a bank which chooses to adapt its Web portal to interact +with the Taler wallet. This interaction is supposed to occur when +the user is sending a SEPA transfer to some mint (i.e. he is creating +a new reserve). + +Through this interaction, the wallet can generate a new reserve's public +key and insert it into the 'subject' field of the transfer without manual +copy&paste. Secondly, the wallet is then able to fetch the amount to be +tranferred to the mint directly from the Web form, in order to poll the mint +to check if the desired amount has been transferred. + +---------------------- +Mutual acknowledgement +---------------------- + +The mutual acknowledgement between a wallet and a bank portal occurs when +the user is on the page which hosts the SEPA form, and is realized by the +mean of JavaScript signals issued on the `body` HTML element. + +When the bank wants to notify to a wallet, it sends the following event: + + .. js:data:: taler-wire-probe + +This event must be sent from a callback for the `onload` event of the +`body` element, otherwise the extension would have not time to +register a listener for this event. It also needs to be sent when +the Taler extension is dynamically loaded, like when the user activates +the extension while he is on the SEPA form page. This is done by +listening for the + + .. js:data:: taler-load + +event. If the Taler extension is present, it will respond with a + + .. js:data:: taler-wallet-present + +event. The handler should then activate its mechanism to trigger the generation +of a new reserve key in the wallet, for example by updating the DOM to enable a +dedicated button. + +If the Taler extension is unloaded while the user is visiting a SEPA form page, +the page should listen for a + + .. js:data:: taler-unload + +event, in order to hide the previously enabled button. + +------------------------- +How to trigger the wallet +------------------------- + +This interaction will make the wallet generate a new reserve public key, +as well as allowing the user to choose his wanted mint. Finally, the wallet +will directly paste this information inside the SEPA form and submit it. +Lastly, it allows the wallet to fetch the desired amount to be transferred +to the mint from the SEPA form. Typically, this trigger is initiated by the +user pushing a button while he is on the page which hosts the SEPA Web form. + +The wallet listens to a + + .. js:data:: taler-create-reserve + +event, through which it expects to receive the following object: + +.. sourcecode:: javascript + + {form_id: sepa-form-id, + input_amount: input-amount-id, + input_pub: input-pub-id, + mint_rcv: receiving-money-mint} + +`input_amount` is the `id` attribute of the HTML `input` element which +hosts the amount to wire to the desired mint. Please note that the wallet will +only accept amounts of the form `n[.x[y]] CUR`, where `CUR` is the ISO code +of the specified currency. So it may be necessary for the bank's webmaster to +preprocess this data to give it to the wallet in the right format. + +`input_pub` must be the `id` attribute of the `input` element within the form +which represents this SEPA transfer's "subject". +`form_id` must be the `id` attribute of the SEPA `form` element (needed by the wallet to +call `submit()` on it). +Finally, `mint_rcv` is the `id` attribute of the `input` element within the form +from which the server side handler of this form will fetch the mint base URL to issue +`/admin/add/incoming` on; see :ref:`add-incoming`. + +The following source code highlights the key steps for adding the Taler button +to trigger the wallet on a SEPA form page: + +.. sourcecode:: javascript + + function has_taler_wallet_callback(aEvent){ + // This function is called if a Taler wallet is available. + // suppose the radio button for the Taler option has + // the DOM ID attribute 'taler-wallet-trigger' + var tbutton = document.getElementById("taler-wallet-trigger"); + tbutton.removeAttribute("disabled"); + }; + + function taler_wallet_load_callback(aEvent){ + // let the Taler wallet know that this is a SEPA form page + // which supports Taler (the extension will have + // missed our initial 'taler-wire-probe' from onload()) + document.body.dispatchEvent(new Event('taler-wire-probe')); + }; + + function taler_wallet_unload_callback(aEvent){ + // suppose the button which triggers the wallet has + // the DOM ID attribute 'taler-wallet-trigger' + var tbutton = document.getElementById("taler-wallet-trigger"); + tbutton.setAttribute("disabled", "true"); + }; + +.. sourcecode:: html + + <body onload="function(){ + // First, we set up the listener to be called if a wallet is present. + document.body.addEventListener("taler-wallet-present", has_taler_wallet_callback, false); + // Detect if a wallet is dynamically added (rarely needed) + document.body.addEventListener("taler-load", taler_wallet_load_callback, false); + // Detect if a wallet is dynamically removed (rarely needed) + document.body.addEventListener("taler-unload", taler_wallet_unload_callback, false); + // Finally, signal the wallet that this is a payment page. + document.body.dispatchEvent(new Event('taler-wire-probe')); + };"> + ... + </body> diff --git a/index.rst b/index.rst @@ -31,6 +31,7 @@ Protocol Specification: api-mint api-merchant + banks Implementation: