summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api-common.rst4
-rw-r--r--api-exchange.rst13
-rw-r--r--api-merchant.rst116
-rw-r--r--dev-merchant.rst4
-rw-r--r--example-essay-store.rst20
-rw-r--r--integration-merchant.rst230
-rw-r--r--operate-exchange.rst6
-rw-r--r--operate-merchant.rst10
8 files changed, 331 insertions, 72 deletions
diff --git a/api-common.rst b/api-common.rst
index 3bbc8722..d44e55ec 100644
--- a/api-common.rst
+++ b/api-common.rst
@@ -70,8 +70,8 @@ handle the error as if an internal error (500) had been returned.
interface ErrorDetail {
- // Numeric error code. See "taler_error_codes.h".
- error_code: number;
+ // Numeric error code unique to the condition. See "taler_error_codes.h".
+ 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.
diff --git a/api-exchange.rst b/api-exchange.rst
index e2af539e..e6d5c93a 100644
--- a/api-exchange.rst
+++ b/api-exchange.rst
@@ -360,7 +360,7 @@ exchange.
// `base32`_ encoding of `TALER_WithdrawRequestPS`_ with purpose TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW. This field appears only if `type` is "WITHDRAW".
details?: string;
- // Signature over the transaction `details`.
+ // Signature over the transaction `details` (FIXME: Which transaction, which details?).
signature?: EddsaSignature;
}
@@ -392,7 +392,7 @@ exchange.
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 402 Payment Required:
+ :status 403 Forbidden:
The balance of the reserve is not sufficient to withdraw a coin of the indicated denomination.
The response is `WithdrawError`_ object.
@@ -475,7 +475,7 @@ denomination.
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:
+ :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`_.
@@ -549,7 +549,7 @@ denomination.
// The string constant "DEPOSIT_OK"
status: string;
- // the EdDSA signature of `TALER_DepositConfirmation`_ using a current
+ // the EdDSA signature of `TALER_DepositConfirmationPS`_ using a current
// `signing key of the exchange <sign-key-priv>`_ 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.
@@ -823,7 +823,7 @@ the API during normal operation.
gamma_tp: EddsaPublicKey;
// Specific `gamma` value chosen by the exchange.
- gamma: Integer;
+ gamma: number;
}
@@ -946,6 +946,7 @@ typically also view the balance.)
The wire transfer identifier is unknown to the exchange.
.. _TrackTransferResponse:
+ .. _tsref-type-TrackTransferResponse:
.. code-block:: tsref
interface TrackTransferResponse {
@@ -978,7 +979,7 @@ typically also view the balance.)
.. _tsref-type-TrackTransferDetail:
.. code-block:: tsref
- interface WireDepositDetail {
+ interface TrackTransferDetail {
// SHA-512 hash of the contact of the merchant with the customer.
H_contract: HashCode;
diff --git a/api-merchant.rst b/api-merchant.rst
index e8c9c9cd..885a679e 100644
--- a/api-merchant.rst
+++ b/api-merchant.rst
@@ -77,7 +77,7 @@ The Frontent HTTP API
// The merchant instance which is going to receive the final wire transfer.
// See `instances-lab`_
- receiver: string;
+ instance: string;
// Signature of `TALER_ContractPS`_
merchant_sig: EddsaSignature;
@@ -85,9 +85,16 @@ The Frontent HTTP API
// a timestamp of this deposit permission. It equals just the contract's timestamp
timestamp: Timestamp;
- // same value held in the contract's `refund` field
+ // 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;
@@ -158,8 +165,8 @@ The following API are made available by the merchant's `backend` to the merchant
* `H_wire`
* `merchant_pub`
- The frontend may or may not provide a `receiver` field in the proposition, depending on its logic.
- The ``default`` instance will be used if no `receiver` field is found by the backend.
+ 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**
@@ -176,10 +183,10 @@ The following API are made available by the merchant's `backend` to the merchant
**Request:**
The `frontend` passes the :ref:`deposit permission <DepositPermission>`
- received from the wallet, and optionally adding a field named `pay_deadline`,
+ 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 `pay_deadline` must be after the `refund_deadline`.
- The backend calculates the `pay_deadline` by adding the `wire_transfer_delay`
+ 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:**
@@ -222,18 +229,67 @@ The following API are made available by the merchant's `backend` to the merchant
: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: identificative token of the merchant :ref:`instance <instances-lab>` 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:`TrackTransactionResponse <TrackTransferResponse>`. Note that
+ The body of the response is a :ref:`TrackTransferResponse <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; // FIXME: define/link-to this object
+
+ // 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.
@@ -241,7 +297,7 @@ The following API are made available by the merchant's `backend` to the merchant
**Request:**
:query id: ID of the transaction we want to trace (an integer)
- :query receiver: 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.
+ :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:**
@@ -260,6 +316,8 @@ The following API are made available by the merchant's `backend` to the merchant
: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:**
@@ -293,6 +351,35 @@ The following API are made available by the merchant's `backend` to the merchant
deposit_fee: Amount;
}
+ .. _TransactionConflictProof:
+ .. _tsref-type-TransactionConflictProof:
+ .. code-block:: tsref
+
+ interface TransactionConflictProof {
+ // Numerical error code
+ code: number; // FIXME Point to some error codes list
+
+ // 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:get:: /history
Returns transactions up to some point in the past
@@ -314,7 +401,7 @@ The following API are made available by the merchant's `backend` to the merchant
// Hashcode of the relevant contract
h_contract: HashCode;
-
+
// Exchange's base URL
exchange: string;
@@ -396,7 +483,7 @@ The `contract` must have the following structure:
// 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)
+ // List of products that are part of the purchase (see `below <Product>`_)
products: Product[];
// Time when this contract was generated
@@ -415,9 +502,9 @@ The `contract` must have the following structure:
// More info about the merchant, see below
merchant: Merchant;
- // Which instance is participating in this contract. See the paragraph `Merchant Instances`.
- // This field is optional, as the "default" instance is not forced to provide any `receiver` identificator.
- receiver: string;
+ // Which instance is participating in this contract. See `Merchant Instances <instances-lab>`_.
+ // 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;
@@ -436,6 +523,7 @@ The `contract` must have the following structure:
The `product` object describes the product being purchased from the merchant. It has the following structure:
+ .. _Product:
.. _tsref-type-Product:
.. code-block:: tsref
diff --git a/dev-merchant.rst b/dev-merchant.rst
index cb834659..faa2a28c 100644
--- a/dev-merchant.rst
+++ b/dev-merchant.rst
@@ -29,13 +29,13 @@ Design
TO REVIEW::
- The `frontend` is the existing shopping portal of the merchant.
+ The 'frontend' is the existing shopping portal of the merchant.
The architecture tries to minimize the amount of modifications necessary
to the `frontend` as well as the trust that needs to be placed into the
`frontend` logic. Taler requires the frontend to facilitate two
JSON-based interactions between the wallet and the `backend`, and
one of those is trivial.
- The `backend` is a standalone C application intended to implement all
+ The 'backend' is a standalone C application intended to implement all
the cryptographic routines required to interact with the Taler wallet
and a Taler exchange.
diff --git a/example-essay-store.rst b/example-essay-store.rst
index 2a240f86..ec22ff42 100644
--- a/example-essay-store.rst
+++ b/example-essay-store.rst
@@ -20,21 +20,17 @@
Example: Essay Store
==================================
-To properly understand this example, the reader should be familiar with Taler's terminology;
-in particular, definitions like `contract`, `fulfillment URL`, `offering URL`, and `deposit permission`,
-are assumed to be known. Refer to :ref:`contract`, :ref:`payprot` and :ref:`deposit-par` in order to get
-some general insight on terms and interactions between components.
+This section shows how to set up a merchant :ref:`frontend <merchant-arch>`, and is
+inspired by our demonstration shop running at `https://blog.demo.taler.net/`.
-This section describes how the demonstrator essay store interacts with the Taler system. As for Taler's
-terminology, the demonstrator essay store is an example of `frontend`.
-This demonstrator's code is hosted at `git://taler.net/merchant-frontends/talerfrontends/blog/` and is
-implemented in Python.
+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 essay store, available at https://blog.demo.taler.net, is such that its homepage
-is a list of titles from buyable articles and each title links to an `offer URL`.
-In particular, the offer URLs have the following format:
+The desired effect is that the homepage has a list of buyable article, and once the
+user clicks on one of them, they will either get the Taler :ref:`contract <contract>`
+or a credit card paywall if they have no Taler wallet installed.
- `https://blog.demo.taler.net/essay/article_title`
The offer URLs trigger the expected interaction with the wallet. In practical terms, the
offer URL returns a HTML page that can either show a pay-form in case Taler is not installed
diff --git a/integration-merchant.rst b/integration-merchant.rst
index b07f1339..f3221617 100644
--- a/integration-merchant.rst
+++ b/integration-merchant.rst
@@ -31,26 +31,27 @@ Interaction with merchant websites
The payment process
+++++++++++++++++++
-By design, the Taler payment process ensures the following three properties:
+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 again retrieve the online resource he paid for.
+ 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 `replay the payment` we mean reusing the `same coins` used to pay for
+ 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 will NOT subtract further credit from the user's total budget.
+ So the replay does NOT subtract further credit from the user's total budget.
-3. The user must be able to *share* the link to both the page with the unpaid offer or
- the order status page. If the links are shared with another user, they should
- typically allow the other user to perform the same purchase (assuming the item
- is still available).
+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).
+(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
@@ -61,9 +62,17 @@ 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 have a *fulfillment URL* which is in charge of doing
-two thigs: give to the user what he paid for, or redirect the user
-to the offer URL in case he did not pay.
+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
@@ -106,6 +115,8 @@ 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
---------------
@@ -113,9 +124,19 @@ 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, this is done by FIXME, whereas
-in case of "402 Payment Required", a `X-Taler-contract-url` HTTP header will
-be set to the contract's location. (FIXME: is that right?).
+contract. In case of JavaScript interaction, the merchant should just return
+a page whose javascript contains an invocation to ``offerContractFrom(<CONTRACT-URL>)``
+from ``taler-wallet-lib``. This function will download the contract from
+`<CONTRACT-URL>` 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
@@ -123,31 +144,172 @@ 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 when the user is not
-visiting a fulfillment URL he got from someone else, it is the wallet
-which points the browser to a fulfillment URL after the user accepts
-the contract.
+accounted in the fulfillment URL. Note that after the user accepts a
+contract, the wallet will automatically point the browser to the
+fulfillment URL.
-A fulfillment URL must carry all the details necessary to reconstruct
-a contract. For simple contracts, a Web shop should encode the unique
-contract details (in particular, the transaction identifier) in the
-URL. This way, the Web shop can generate fulfillment URLs without
-actually having to write the full contract proposal to its database.
-This allows the merchant to delay disk (write) operations until
-customers actually pay.
+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.
-Once the payment process has been started, the merchant will then
-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, they are:
+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`
-By looking at `X-taler-contract-hash`, the wallet can face two situations:
+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
+
+ <html>
+ <head>
+ <script src="path/to/taler-wallet-lib.js"></script>
+ <script type="application/javascript">
+ // Imported from taler-wallet-lib.js
+ taler.executePayment(<CONTRACT-HASHCODE>, <PAY-URL>, <OFFERING-URL>);
+ </script>
+ </head>
+ ..
+
+ </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 `<PAY-URL>` if `<CONTRACT-HASH>` is found in its database (meaning that the user accepted it).
+2. Redirect the browser to `<OFFER-URL>`, if `<CONTRACT-HASH>` 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 <merchant-arch>`,
+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 <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
+
+ <html>
+ ...
+ <h3><a href="/essay/How_to_write_a_frontend">How to write a frontend</a></h3>
+ ...
+ </html>
+
+whence the offer URL design is as follows::
+
+ https://<BASEURL>/essay/<ARTICLE-NAME>
+
+`<ARTICLE-NAME>` 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 <offer>`_ 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://<BASEURL>/essay/<ARTICLE-NAME>?tid=<TRANSACTION-ID>&timestamp=<TIMESTAMP>
+
+.. 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 `<ARTICLE-NAME>` 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 `<ARTICLE-NAME>`, `<TRANSACTION-ID>` and
+`<TIMESTAMP>` to the frontend in order to get the contract's hashcode.
+
+See `above <fulfillment>`_ 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[<HASHCODE>] = {'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 `<HASHCODE>` as the key is to prevent the wallet to send bogus
+parameters along the fulfillment URL. `<HASHCODE>` 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)
-1. This hashcode is already present in the wallet's database, so the wallet can send the payment to `X-taler-pay-URL`. During this operation, the wallet associates the data it sent to `X-taler-pay-URL` with the received hashcode, so that it can replay payments whenever it gets this hashcode again.
-2. This hashcode is unknown to the wallet, so the wallet can point the browser to `X-taler-offer-URL`, so the user will get the contract and decide to accept it or not. This happens when the user gets the fulfillment URL from someone else.
+ # 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)
+
-FIXME: explain the JavaScript way
+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
index 9ae11061..06dee2f2 100644
--- a/operate-exchange.rst
+++ b/operate-exchange.rst
@@ -167,6 +167,12 @@ Keys duration
Both `signkeys` and `denom keys` have a :ref:`starting date <keys-duration>`. 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.
+++++++++++++
+Installation
+++++++++++++
+
+TBD
+
+++++
Other
+++++
diff --git a/operate-merchant.rst b/operate-merchant.rst
index 418534be..d5103115 100644
--- a/operate-merchant.rst
+++ b/operate-merchant.rst
@@ -123,7 +123,7 @@ the chosen wireformat. In our demo, we have::
wireformat = test
..
- [default-wireforma]
+ [merchant-instance-wireformat-default]
test_response_file = ${TALER_CONFIG_HOME}/merchant/wire/test.json
The file `test.json` obeys to the following specification
@@ -177,9 +177,15 @@ instance `Tor` as follows::
..
- [Tor-wireformat]
+ [merchant-instance-wireformat-Tor]
TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/merchant/wire/tor.json
Please note that :ref:`Taler messagging<merchant-api>` 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
+++++++++++++
+
+TBD