summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-08-25 14:12:39 +0200
committerChristian Grothoff <christian@grothoff.org>2016-08-25 14:12:39 +0200
commit54d20ecb881711cfebd47e5496352dcb4f51940d (patch)
tree6f9fd320740ff459afe2349307ab0d7fa7659b2f
parent73679de45997bf999a4dd1264d10e7c27b2799f8 (diff)
parentbbbde6979f7e8f7fd22e5c2e7be550ed79408be0 (diff)
downloaddocs-54d20ecb881711cfebd47e5496352dcb4f51940d.tar.gz
docs-54d20ecb881711cfebd47e5496352dcb4f51940d.tar.bz2
docs-54d20ecb881711cfebd47e5496352dcb4f51940d.zip
Merge branch 'master' of git.taler.net:api
-rw-r--r--api-exchange.rst2
-rw-r--r--api-merchant.rst37
-rw-r--r--example-essay-store.rst135
-rw-r--r--exchange-db.pngbin202763 -> 198095 bytes
-rw-r--r--integration-merchant.rst156
5 files changed, 102 insertions, 228 deletions
diff --git a/api-exchange.rst b/api-exchange.rst
index e4842444..1ed3eaf6 100644
--- a/api-exchange.rst
+++ b/api-exchange.rst
@@ -442,6 +442,7 @@ exchange.
history: TransactionHistoryItem[]
}
+.. _deposit-par:
--------------------
Deposit
@@ -456,6 +457,7 @@ denomination.
.. _deposit:
+
.. http:POST:: /deposit
Deposit the given coin and ask the exchange to transfer the given :ref:`amount`
diff --git a/api-merchant.rst b/api-merchant.rst
index 71f9a302..9c1adf9b 100644
--- a/api-merchant.rst
+++ b/api-merchant.rst
@@ -23,9 +23,9 @@ Merchant API
Before reading the API reference documentation, it is suggested to read the :ref:`merchant-arch`
-------------------------------
+---------------------
The Frontent HTTP API
-------------------------------
+---------------------
.. http:get:: contract_url
@@ -71,6 +71,9 @@ The Frontent HTTP API
// maximum fees merchant agreed to cover as per the contract
max_fee: Amount;
+ // The merchant instance which is going to receive the final wire transfer. See paragraph `Merchant Instances`
+ receiver: string;
+
// signature by the merchant over the contract, must match signed data of purpose TALER_SIGNATURE_MERCHANT_CONTRACT
merchant_sig: EddsaSignature;
@@ -143,20 +146,20 @@ The following API are made available by the merchant's `backend` to the merchant
**Request:**
- The `proposition` that is to be sent from the frontend is a `contract` object without the fields
+ The `proposition` that is to be sent from the frontend is a `contract` object *without* the fields
* `exchanges`
* `auditors`
* `H_wire`
* `merchant_pub`
- The `backend` then completes this information based on its configuration.
+ 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.
**Response**
:status 200 OK:
- The backend has successfully created the contract. It responds with an :ref:`offer <offer>`. This request should virtually always be successful.
- On success, the `frontend` should pass this response verbatim to the wallet.
+ The backend has successfully created the contract. It responds with an :ref:`offer <offer>`. On success, the `frontend` should pass this response verbatim to the wallet.
:status 403 Forbidden:
The frontend used the same transaction ID twice. This is only allowed if the response from the backend was lost ("instant" replay), but to assure that frontends usually create fresh transaction IDs this is forbidden if the contract was already paid. So attempting to have the backend sign a contract for a contract that was already paid by a wallet (and thus was generated by the frontend a "long" time ago), is forbidden and results in this error. Frontends must make sure that they increment the transaction ID properly and persist the largest value used so far.
@@ -225,7 +228,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`.
**Response:**
:status 200 OK:
@@ -282,6 +285,20 @@ Encodings
Data such as dates, binary blobs, and other useful formats, are encoded as described in :ref:`encodings-ref`.
+.. _instances:
+
+------------------
+Merchant Instances
+------------------
+
+Any backend can account for multiple bank accounts, and we call `instance` or `receiver` (interchangeably)
+any of those bank accounts. The backend needs that due to the ability we give to a merchant to route money
+(he earns through Taler) to multiple bank accounts, depending on his will. For example, a donation shop using
+Taler needs to know any bank account of any entity which is going to receive money through his website. That
+happens because when the merchant deposits coins to the exchange, he must provide bank details to it about the
+money receiver, see :ref:`deposit-par`.
+
+
.. _contract:
Offer and Contract
@@ -359,7 +376,11 @@ The `contract` must have the following structure:
// More info about the merchant, see below
merchant: Merchant;
- // The hash of the merchant's wire details.
+ // 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;
+
+ // The hash of the merchant instance's wire details.
H_wire: HashCode;
// Any exchanges audited by these auditors are accepted by the merchant.
diff --git a/example-essay-store.rst b/example-essay-store.rst
index 042c5233..a780cdc2 100644
--- a/example-essay-store.rst
+++ b/example-essay-store.rst
@@ -16,138 +16,27 @@
Example: Essay Store
==================================
-..
- 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
+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 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`
+This demonstrator's code is hosted at `git://taler.net/merchant-frontends/talerfrontends/blog/` and is
+implemented in Python.
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:`byoffer`). 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.
-
-Once the user visits the offering URL by clicking on some article's title, the merchant
-
-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:`byoffer` is true.
-
-2. checks if the user gave additional parameters to the URL above, actually making it a
- fulfillment URL. If so, jump to point `y`.
-
-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:`byoffer`.
-
-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).
-
-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:`byoffer`.
- 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).
-
-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.
+is a list of titles from buyable articles and each title links to an `offering URL`.
+In particular, the offering URL has the following format:
-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.
+ `https://blog.demo.taler.net/essay/article_title`
- `https://blog.demo.taler.net/essay_fulfillment.php?article=articleId&tid=3489&timestamp=8374738`
+As for the fulfillment URL, it matches the initial part of an offering URL, but contains also
+those parameters needed to reconstruct the contract, which are `tid` (transaction id) and `timestamp`.
+So a fulfillment URL looks like:
-----------------------
-IIG by fulfillment URL
-----------------------
+ `https://blog.demo.taler.net/essay/article_title?tid=3489&timestamp=8374738`
-TBD
+We did not need to include any further details in the fulfillment URL because most of them
+do not change in the time, and for simplicity all the articles have the same price.
diff --git a/exchange-db.png b/exchange-db.png
index de4c6570..ddc25591 100644
--- a/exchange-db.png
+++ b/exchange-db.png
Binary files differ
diff --git a/integration-merchant.rst b/integration-merchant.rst
index 76a9ae5a..b4e623a9 100644
--- a/integration-merchant.rst
+++ b/integration-merchant.rst
@@ -18,115 +18,77 @@ Interaction with merchant websites
.. _payprot:
-++++++++++++++++
-Payment protocol
-++++++++++++++++
-
-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
-
-* offering URL
-* fulfillment URL
-
-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.
-
-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.
-
-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.
-
-.. _byoffer:
-
----------------------
-IIG by `offering` URL
----------------------
-
-0. If the state associated to the resource requested is `payed`, go to 7.
-
-1. The merchant sends the following object embedded in a `taler-confirm-contract` event
++++++++++++++++++++
+The payment process
++++++++++++++++++++
+
+Before delving into the technical details, it is worth surveying the payment process from an
+abstract point of view. By design, Taler implements the following three points:
+
+0. The user must accept a contract before paying for something
+1. The bought item(s) must be made available again in the future by the merchant to the customer
+ (in case of physical items, this point means that the merchant must provide the receipt again
+ in the future to the customer)
+2. The user must be able to *share* what he bought; in other words, we want a URI which would
+ hold any information about the purchase (and therefore the contract), like which items the
+ user bought and any other relevant detail. This way, any person who may get in possession
+ of this URI may repeat the same purchase.
+
+In Taler terminology, we call an *offering URL* an URL of the merchant's website that triggers
+the generation of a contract, being it automatically or requiring the user interaction. For example,
+some merchants may implement the offering URL such that it just returns the contract's JSON, and
+some other may implement it as a shopping chart page where the user can then confirm its purchase and
+get the contract JSON. We call a *fulfillment URL* an URL of the merchant's website which implements
+points 1. and 2. For example, let's say that Alice bought a movie and a picture, and the fulfillment URL
+for this purchase is *http://merchant.example.com/fulfillment?x=8ru42*. Each time Alice visits
+*http://merchant.example.com/fulfillment?x=8ru42* she gets the same movie and picture. If then Alice
+decides to give Bob this URL and he visits it, then he can decide to buy or not the same movie and
+picture.
+
+---------------
+Payment 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. Since each fulfillment URL carries all the
+details useful to reconstruct a contract, the merchant reconstructs the contract and sends back to
+the user's browser a `taler-execute-payment` DOM event, defined as follows:
.. code-block:: tsref
{
- // 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;
- };
-
- // 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
+ // base32 encoding of the Contract's hashcode
H_contract: string;
- // URL where to send deposit permission
+ // URL where to send the deposit permission (AKA coins)
pay_url: string;
- // Used in 'IIG by fulfillment URL'
+ // Offering 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
+This event is listened to by the wallet which can take two decisions based on the `H_contract`
+field: if `H_contract` is known to the wallet, then the user has already accepted the contract
+for this purchase and the wallet will send a deposit permission to `pay_url`. If that is not the
+case, then the wallet will visit the `offering_url` and the user will decide whether or not to
+accept the contract. Once `pay_url` receives and approves the deposit permission, it sets the session
+state for the claimed item(s) to ``payed`` and now the wallet can point again the browser to the
+fulfillment URL and finally get the claimed item(s). It's worth noting that each deposit permission
+is associated with a contract and the wallet can reuse the same deposit permission to get the item(s)
+mentioned in the contract without spending new coins.
-.. _ffil:
+------------
+The contract
+------------
-------------------------
-IIG by `fulfillment` URL
-------------------------
+As said, the offering URL is a location where the user must pass by in order to get a contract, and
+the contract is handed by the merchant to the browser by the mean of a `taler-confirm-contract` DOM
+event, defined as follows:
-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
+ .. code-block:: tsref
-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.
+ {
+ contract_wrapper: Offer;
+ }