taler-docs

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

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:
Mapi-bank.rst | 14+++++++++++---
Mapi-merchant.rst | 12+++++++-----
Mdiagram.dot | 27+++++++++++++++++++--------
Mexample-essay-store.rst | 158++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mglobal_licensing.rst | 21++++++++++++---------
Mintegration-bank.rst | 4+++-
Mintegration-merchant.rst | 144++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
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&timestamp=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&timestamp=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.