commit 03701d91990cb37af5b0d21f5b149030857a5853
parent 461b59a0eae256ac0c5aba9bd6f06414641ac28f
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 31 Mar 2016 19:36:49 +0200
Merge branch 'master' of git+ssh://taler.net/var/git/api
Diffstat:
7 files changed, 289 insertions(+), 91 deletions(-)
diff --git a/api-bank.rst b/api-bank.rst
@@ -51,7 +51,7 @@ the recipient's account
amount: Amount;
// The id of this wire transfer
- wid: base32;
+ wtid: base32;
// The sender's account identificator
debit_account: number;
@@ -66,8 +66,16 @@ the recipient's account
interface BankIncomingError {
- // The reason which made this request fail. Typically due to malfomation
- // of the POST's body
+ // 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-merchant.rst b/api-merchant.rst
@@ -55,14 +55,14 @@ that is legally non-binding:
// The actual contract
contract: Contract;
- // The hash of the contract, provided as a convenience.
- // All components that do not fully trust the
- // merchant must verify this field.
- H_contract: HashCode;
+ // The hash of the contract, encoded in base32, provided
+ // as a convenience. All components that do not fully trust
+ // the merchant must verify this field.
+ H_contract: string;
// Signature over the contract made by the merchant.
// Must confirm to the `Signature specification`_ below.
- sig: EddsaSignature;
+ sig: string;
}
The contract must have the following structure:
@@ -258,6 +258,7 @@ should be set to ``TALER_SIGNATURE_MERCHANT_CONTRACT``.
struct GNUNET_HashCode h_contract;
}
+
---------------------
The Merchant HTTP API
---------------------
@@ -265,6 +266,7 @@ The Merchant HTTP API
In the following requests, ``$``-variables refer to the variables in the
merchant's offer.
+.. _pay:
.. http:post:: $pay_url
Send the deposit permission to the merchant. Note that the URL may differ between
diff --git a/diagram.dot b/diagram.dot
@@ -1,10 +1,21 @@
digraph g {
-size="800,800";
-wallet -> merchant_frontend [label=" buy"];
-merchant_frontend -> merchant_backend [label="internal cooperation"];
-merchant_backend -> merchant_frontend;
-wallet -> exchange [label=" coins withdrawal"];
-merchant_backend -> exchange [label="deposit coins"];
-wallet -> bank [label="wire funds to exchange's account"];
-bank -> exchange [label="notify of wiretransfer"];
+# size="800,800";
+compound=true;
+concatenate=true;
+subgraph cluster_wallet {
+ style=filled;
+ color=lightgrey;
+ webex [label="wallet-webex"];
+ android [label="wallet-android"];
+ legacy [label="wallet-legacy"];
+ label="Wallets";
+}
+android -> merchant_frontend [label="buy", ltail=cluster_wallet];
+merchant_frontend -> merchant_backend [dir="both"];
+merchant_frontend [label="merchant (frontend)"];
+merchant_backend [label="merchant (backend)"];
+android -> exchange [label="withdraw", ltail=cluster_wallet, dir="both"];
+merchant_backend -> exchange [label="deposit"];
+android -> bank [label="select exchange", ltail=cluster_wallet];
+bank -> exchange [label="wire transfer", dir="both"];
}
diff --git a/example-essay-store.rst b/example-essay-store.rst
@@ -10,54 +10,144 @@
You should have received a copy of the GNU Lesser General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- @author Florian Dold
+ @author Marcello Stanisci
==================================
Example: Essay Store
==================================
-The main page of the essay store shows links to essays of the form `/essay?name=:name`.
+..
+ The main page of the essay store shows links to essays of the form `/essay?name=:name`.
+
+ The `/essay` URL takes the following query parameters:
+ * `name`: mandatory, name of the essay
+ * `tid`: optional, transaction ID generated by the merchant for the
+ contract that was used to purchase an instance of the article
+ * `timestamp`, optional, timestamp for the contract that was used to purchase
+ the essay with the given `tid`.
+
+ These are the steps for showing `/essay`. If the wallet is not present in
+ steps 2 and 3, the user agent is redirected to a mock credit card
+ payment page.
+
+ 1. The server checks the status of the the essay with the name `name` in the server-side
+ session state
+
+ * If the essay is marked as payed, display the essay.
+ * Otherwise proceed with step 2
+
+ 2. The server checks if the `tid` and `timestamp` query parameters are present
+
+ * If `tid` and `timestamp` are present, restore the contract for the essay
+ (using `tid` as transaction id in the contract, `timestamp` as timestamp
+ and `timestamp+REFUND_DELTA` as refund deadline) and emit the
+ `taler-execute-contract` DOM event in the user agent.
+ * Otherwise proceed with step 3
+
+ 3. The server generates a new contract and emits the `taler-confirm-contract` DOM event in the user agent,
+ with the essay name as repurchase correlation identifier and `/essay?name=:name?tid=:tid` as fulfillment url.
+
+
+ In step 2, the `taler-execute-contract` event has the following parameters:
+
+ * `H_contract`: hash of the contract that was restored
+ * `payment_url`: The internal URL `/pay?H_contract=...` of the essay store,
+ will set the server-side session state for the article associated with the
+ contract hash on successful coin deposit. The contract hash is associated
+ with the article name in the server-side session state when the contract is restored.
+ * `offer_url`: Link to a teaser page (`/teaser?name=...`), which also contains a link to the article
+ page, without the `tid` parameter.
+
+
+ Note that we assume that all essays cost the same (otherwise the amount would have to be included in
+ the restoration information in the /essay fulfillment URL). The refund deadline is computed
+ by adding the merchant-specific constant `REFUND_DELTA` to the contract's timestamp.
+
+..
+ Describing implementation of the above scenario
+
+--------------
+Before reading
+--------------
+To properly understand this example, the reader should be familiar with Taler's terminology;
+in particular, definitions like `contract`, `fulfillment URL`, `offering URL`, `IIG` and `deposit permission`,
+are assumed to be known. Refer to :ref:`contract`, :ref:`payprot` and :ref:`deposit` in order to get
+some general insight on terms and interactions between components.
+
+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 lies in `examples/blog` of `git://taler.net/merchant/examples/blog`
+
+The essay store, available at https://blog.demo.taler.net, is such that its homepage
+is a list of buyable articles and each article is a reference to an `offering
+URL` (see :ref:`offer`). In particular, this offering URL has the following format:
+
+ `https://blog.demo.taler.net/essay_fulfillment.php?article=articleId`
+
+It is worth noting that in our implementation the `offering` and the `fulfillment` URLs
+differ only respect to the parameters given to the path `/essay_fulfillment.php`. Namely,
+the offering URL becomes a fulfillment URL whenever the user adds the parameters needed to
+reconstruct the contract, which are `tid` (transaction id) and `timestamp`
+(see :ref:`contract`, and :ref:`ffil`). For the sake of completeness,
+
+
+ `https://blog.demo.taler.net/essay_fulfillment.php?article=articleId&tid=3489×tamp=8374738`
+
+would be a fulfillment URL.
-The `/essay` URL takes the following query parameters:
- * `name`: mandatory, name of the essay
- * `tid`: optional, transaction ID generated by the merchant for the
- contract that was used to purchase an instance of the article
- * `timestamp`, optional, timestamp for the contract that was used to purchase
- the essay with the given `tid`.
+Once the user visits the offering URL by clicking on some article's title, the merchant
-These are the steps for showing `/essay`. If the wallet is not present in
-steps 2 and 3, the user agent is redirected to a mock credit card
-payment page.
+1. checks if the state associated to this article corresponds to "payed". If this is the
+ case, point 7. is triggered, which is what happens when point 0 of :ref:`offer` is true.
-1. The server checks the status of the the essay with the name `name` in the server-side
- session state
+2. checks if the user gave additional parameters to the URL above, actually making it a
+ fulfillment URL. If so, jump to point `y`.
- * If the essay is marked as payed, display the essay.
- * Otherwise proceed with step 2
+3. returns a page which can detect if a Taler wallet is installed in the user's browser and,
+ if so, automatically downloads the contract from the merchant; if not, displays a paywall
+ for credit card payment. Note that the contract's request is entirely managed by the page's
+ JavaScript and not by the wallet; that gives more flexibility to the merchants by reducing
+ the communication between wallets and shops. The wallet gets involved once the
+ contract arrives and the JavaScript fires a `taler-confirm-contract` event containing the
+ contract, see point 1. of :ref:`offer`.
-2. The server checks if the `tid` and `timestamp` query parameters are present
+4. the wallet visits the fulfillment URL associated with this purchase (the fulfillment
+ URL's path is indicated in the contract, so the wallet has to just add `tid` and `timestamp`
+ to it).
- * If `tid` and `timestamp` are present, restore the contract for the essay
- (using `tid` as transaction id in the contract, `timestamp` as timestamp
- and `timestamp+REFUND_DELTA` as refund deadline) and emit the
- `taler-execute-contract` DOM event in the user agent.
- * Otherwise proceed with step 3
+5. the same script as in point 1. gets executed, but this time it detects that the user is visiting
+ a fulfillment URL. The script can now reconstruct the contract and store its hash in the state.
+ The hash is stored in an associative array having resource names as keys; in this case the key
+ `articleId` points to the contract's hash. This way is easier to detect if a resource which is
+ to be payed is actually mentioned in the deposit permission. Without this control, a malicious
+ wallet can send a deposit permission for `articleA` and get the resource `articleB`, see point 6.
+ As a last step, the script returns a page which fires a `taler-execute-payment` event in the user's
+ browser carrying the same data structure as in point 4. of :ref:`offer`.
+ Note that both in point 3. and 5. the HTML page returned is the same, namely it is the page showing
+ the credit card payment. It is designed so that it is possible to `inject` the event to fire at the
+ user's browser. So in point 3. the injected event is `taler-confirm-contract`, and in point 5. is
+ `taler-execute-payment`. This way if the Taler wallet responds to the event, then the payment is
+ kept Taler-style, otherwise the user just sees a credit card form (without making further requests).
-3. The server generates a new contract and emits the `taler-confirm-contract` DOM event in the user agent,
- with the essay name as repurchase correlation identifier and `/essay?name=:name?tid=:tid` as fulfillment url.
+6. the wallet POSTs the deposit permission to `pay_url`, which is
+ `https://blog.demo.taler.net/essay_pay.php?article=articleId`
+
+ This step is responsible for setting the state for `articleId` as payed; to that end it uses
+ `articleId` as the key to get `H_contract` from the state and checks if `H_contract` equals
+ the contract's hash contained in the deposit permission. If they are equal, then the deposit
+ permission is forwarded to the backend. If the backend return a HTTP status 200, then `essay_pay.php`
+ sets the state for `articleId` as payed and notify the wallet about the payment's outcome.
+ If the backend reports any problem, `essay_pay.php` will just forward the data gotten from the
+ backend to the wallet, which will be in charge of managing the error.
-In step 2, the `taler-execute-contract` event has the following parameters:
+7. the wallet visit the fulfillment URL, but now the state for `articleId` is set to payed, so the
+ script will just show the wanted article.
-* `H_contract`: hash of the contract that was restored
-* `payment_url`: The internal URL `/pay?H_contract=...` of the essay store,
- will set the server-side session state for the article associated with the
- contract hash on successful coin deposit. The contract hash is associated
- with the article name in the server-side session state when the contract is restored.
-* `offer_url`: Link to a teaser page (`/teaser?name=...`), which also contains a link to the article
- page, without the `tid` parameter.
+ `https://blog.demo.taler.net/essay_fulfillment.php?article=articleId&tid=3489×tamp=8374738`
+----------------------
+IIG by fulfillment URL
+----------------------
-Note that we assume that all essays cost the same (otherwise the amount would have to be included in
-the restoration information in the /essay fulfillment URL). The refund deadline is computed
-by adding the merchant-specific constant `REFUND_DELTA` to the contract's timestamp.
+TBD
diff --git a/global_licensing.rst b/global_licensing.rst
@@ -52,6 +52,7 @@ 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
@@ -77,6 +78,7 @@ 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
@@ -132,11 +134,11 @@ 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
+* 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)
@@ -194,10 +196,11 @@ 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.
+* 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.
+++++++++++++++++++++++++++++++++++++++++
diff --git a/integration-bank.rst b/integration-bank.rst
@@ -61,10 +61,12 @@ The event data must be a `CreateReserveDetail`_:
// amount_currency
// reserve_pub
// exchange
+ // type ("TEST" or "SEPA")
+ // account_number (which account number has this exchange at this bank)
callback_url: string;
// list of wire transfer types supported by the bank
- // e.g. "SEPA", "test"
+ // e.g. "SEPA", "TEST"
wt_types: Array<string>
}
diff --git a/integration-merchant.rst b/integration-merchant.rst
@@ -1,50 +1,132 @@
+..
+ 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 <http://www.gnu.org/licenses/>
+
+ @author Marcello Stanisci
+
==================================
Interaction with merchant websites
==================================
--------------
-Purchase Flow
--------------
+.. _payprot:
+
+++++++++++++++++
+Payment protocol
+++++++++++++++++
-The purchase flow consists of the following steps:
+The events described below get triggered when the user confirms its
+purchase on a checkout page, or visits some merchant's resource
+that needs a payment to be visualized. We call this situation `IIG` (Interest
+In some Good). The user can initialize a IIG by visiting one of the following kind
+of URL
-1. UA visits merchant's checkout page
-2. The merchant's checkout page notifies the wallet
- of the contract (``taler-deliver-contract``).
-3. The user reviews the contract inside the wallet
-4. The wallet directs the UA to the payment execution page
-5. The execution page must send the event ``taler-execute-payment`` with
- the contract hash of the payment to be executed.
-6. The wallet executes the payment in the domain context of the
- execution page and emits the ``taler-payment-result`` event
- on the execution page.
-7. The execution page reacts to the payment result (which
- is either successful or unsuccessful) by showing
- an appropriate response to the user.
+* offering URL
+* fulfillment URL
-----------------
-Event Reference
-----------------
+Offering URLs are visited the very first time the user wants to get some resource, whereas
+fulfillment URLs let both the user access bought items later in the future (by bookmarking it)
+and share its purchases with other users. In the last case, the fulfillment URL acts like
+a `pointer to the chart` whose items can be bought by who visits the fulfillment URL.
-.. topic:: ``taler-deliver-contract``
+There is no hard separation between physical and virtual resources since
+the receipt for a physical resource plays the same role of a 100% virtual resource like a
+blog article. In other words, when seeing a pay-per-view blog article on his screen, then
+the user has payed for the article; on the other end, when seeing an electronic receipt of
+a physical good on his screen, the user will receive it by mail.
- The event takes an :ref:`offer <offer>` as event detail.
+IIG triggers different flows according to the user visiting an offering or a fulfillment
+URL. For clarity, below are listed the steps taken when the user visits an offering URL.
-.. topic:: ``taler-execute-payment``
+.. _offer:
- The event takes `H_contract` of a :ref:`Contract <tsref-type-Contract>` as event detail.
+---------------------
+IIG by `offering` URL
+---------------------
-.. topic:: ``taler-payment-result``
+0. If the state associated to the resource requested is `payed`, go to 7.
- The event takes the following object as event detail:
+1. The merchant sends the following object embedded in a `taler-confirm-contract` event
.. code-block:: tsref
{
- // was the payment successful?
- success: boolean;
+ // Contract and cryptographic information
+ contract_wrapper: {
+ contract: Contract;
+ // base32 of the merchant's signature over this contract
+ merchant_sig: string;
+ // base32 of this contract's hashcode
+ H_contract: string;
+ };
- // human-readable indication of what went wrong
- hint: string;
+ // If true, the 'back-button' seen by the user when this contract is to be
+ // payed will not point to this HTML, but to the previous one.
+ replace_navigation: boolean
}
-
+
+2. The wallet's reaction is dual: it can either let the user pay for this contract, or
+ detect whether the user has already payed for this resource by looking at the `repurchase_correlation_id`
+ field in the contract. In the first case, the wallet stores `H_contract` in its local database.
+ If there is a match, the wallet starts a IIG by visiting the fulfillment URL associated with the
+ already-made payment (see :ref:`ffil`)
+
+3. The wallet visits the fulfillment URL (which indicated in the Contract). Since the merchant keeps
+ no state for any purchase, it needs relevant information in the fulfillment URL in order to
+ reconstruct the contract and send the payment to the backend. This information is implicit in the
+ mention of 'fulfillment URL'.
+
+4. When a fulfillment URL is visited, the merchant reconstructs the contract and sends back to
+ the user the a `taler-execute-payment` event which embeds the following object
+
+ .. code-block:: tsref
+
+ {
+ // base32 of the Contract's hashcode
+ H_contract: string;
+
+ // URL where to send deposit permission
+ pay_url: string;
+
+ // Used in 'IIG by fulfillment URL'
+ offering_url: string;
+ }
+
+5. The wallet sends the deposit permission to `pay_url`
+
+6. If the payment is successful, then the merchant sets the state for the bought
+ item to `payed` and communicate the outcome to the wallet (see :ref:`merchant API <pay>` for
+ involved HTTP codes and JSONs)
+
+7. Finally, the wallet can visit again the fulfillment URL and get the payed resource
+ thanks to the `payed` state
+
+.. _ffil:
+
+------------------------
+IIG by `fulfillment` URL
+------------------------
+
+We stress again that the fulfillment URL contains all the information a merchant needs
+to reconstruct a contract.
+
+0. If the state associated to the resource requested is `payed`, get the wanted resource.
+
+1. The user visits a fulfillment URL
+
+2. The merchant replies with the same data structure shown in point 4 above
+
+3. The wallet checks if `H_contract` already exists in its database. If it does not exist,
+ then the wallet will automatically visit the offering URL (by looking at the `offering_url`
+ field) and all the process will restart as in point 1 above. Typically, this occurs when a
+ user visits a fulfillment URL gotten from some other user. If `H_contract` is known, then the
+ wallet takes the associated deposit permission from its database and the process will continue
+ as from point 5 above. Please note that the latter scenario is not double spending since the
+ same coins are spent on the same contract.