merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit f4f8f0264f004a9d89d74f39f61195e1e8139ff0
parent ba7df21ddb46d5203accc6d0ff3935199fd400f7
Author: Marcello Stanisci <marcello.stanisci@inria.fr>
Date:   Wed, 17 Feb 2016 18:40:20 +0100

cleaning up the blog to match http://api.taler.net/example-essay-store.html

Diffstat:
Msrc/frontend_blog/blog_lib.php | 11+++++++++++
Dsrc/frontend_blog/cc_payment.php | 52----------------------------------------------------
Rsrc/frontend_blog/essay_cc_pay-fulfillment.php -> src/frontend_blog/essay_cc-fulfillment.php | 0
Asrc/frontend_blog/essay_cc-payment.html | 41+++++++++++++++++++++++++++++++++++++++++
Dsrc/frontend_blog/essay_checkout.php | 219-------------------------------------------------------------------------------
Msrc/frontend_blog/essay_contract.php | 25+++++++++++++------------
Msrc/frontend_blog/essay_fulfillment.php | 60++++++++++++++++++++++++++++++++----------------------------
Msrc/frontend_blog/essay_offer.php | 10++++------
Msrc/frontend_blog/essay_pay.php | 8++------
Msrc/frontend_lib/config.php | 18+++++++++---------
Msrc/frontend_lib/merchants.php | 14+++++++++-----
Msrc/frontend_lib/util.php | 18++++++++++++++++++
12 files changed, 139 insertions(+), 337 deletions(-)

diff --git a/src/frontend_blog/blog_lib.php b/src/frontend_blog/blog_lib.php @@ -23,4 +23,15 @@ function get_article($name){ return $doc; } +/** + * Fetch the page $page and return its + * DOM. + */ +function get_page($page){ + $content = file_get_contents($page); + $doc = new DOMDocument(); + $doc->loadHTML($content); + return $doc; +} + ?> diff --git a/src/frontend_blog/cc_payment.php b/src/frontend_blog/cc_payment.php @@ -1,52 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <title>Enter your details</title> - <link rel="stylesheet" type="text/css" href="style.css"> -</head> -<?php - if (!isset($_GET['article'])){ - echo "Please select an article to buy"; - die(); - } - else { - session_start(); - $_SESSION['cc_payment'] = true; - $article = $_GET['article']; - } -?> - -<body> - <header> - <div id="logo"> - <svg height="100" width="100"> - <circle cx="50" cy="50" r="40" stroke="darkcyan" stroke-width="6" fill="white" /> - <text x="19" y="82" font-family="Verdana" font-size="90" fill="darkcyan">B</text> - </svg> - </div> - - <h1>Blog site demonstration</h1> - </header> - - <aside class="sidebar" id="left"> - </aside> - - <section id="main"> - <article> - <h1>Enter your details</h1> - <p>We need a few details before proceeding with credit card payment</p> - <form> - First name<br> <input type="text"></input><br> - Family name<br> <input type="text"></input><br> - Age<br> <input type="text"></input><br> - Nationality<br> <input type="text"></input><br> - Gender<br> <input type="radio" name"gender">Male</input> - <input type="radio" name="gender">Female</input><br> - </form> - <?php - echo "<form method=\"post\" action=\"essay_cc_pay-fulfillment.php?article=$article\"><input type=\"submit\"></input></form>"; - ?> - </article> - </section> -</body> -</html> diff --git a/src/frontend_blog/essay_cc_pay-fulfillment.php b/src/frontend_blog/essay_cc-fulfillment.php diff --git a/src/frontend_blog/essay_cc-payment.html b/src/frontend_blog/essay_cc-payment.html @@ -0,0 +1,41 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <title>Enter your details</title> + <link rel="stylesheet" type="text/css" href="style.css"> +</head> +<body> + <header> + <div id="logo"> + <svg height="100" width="100"> + <circle cx="50" cy="50" r="40" stroke="darkcyan" stroke-width="6" fill="white" /> + <text x="19" y="82" font-family="Verdana" font-size="90" fill="darkcyan">B</text> + </svg> + </div> + + <h1>Blog site demonstration</h1> + </header> + + <aside class="sidebar" id="left"> + </aside> + + <section id="main"> + <article> + <h1>Enter your details</h1> + <p>We need a few details before proceeding with credit card payment</p> + <form> + First name<br> <input type="text"></input><br> + Family name<br> <input type="text"></input><br> + Age<br> <input type="text"></input><br> + Nationality<br> <input type="text"></input><br> + Gender<br> <input type="radio" name"gender">Male</input> + <input type="radio" name="gender">Female</input><br> + <input id='article-name' type="hidden" value="{article}"></input> + </form> + <form method="post" action="essay_cc-fulfillment.php?article={article}"> + <input type="submit"></input> + </form> + </article> + </section> +</body> +</html> diff --git a/src/frontend_blog/essay_checkout.php b/src/frontend_blog/essay_checkout.php @@ -1,219 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title>Blog - Payment method - Taler Demo</title> - <link rel="stylesheet" type="text/css" href="style.css"> - <script> - /* - @licstart The following is the entire license notice for the - JavaScript code in this page. - - Copyright (C) 2014,2015 GNUnet e.V. - - The JavaScript code in this page is free software: you can - redistribute it and/or modify it under the terms of the GNU - Lesser General Public License (GNU LGPL) as published by the - Free Software - Foundation, either version 3 of the License, or (at your option) - any later version. The code is distributed WITHOUT ANY WARRANTY; - without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU LGPL for more details. - - As additional permission under GNU LGPL version 3 section 7, you - may distribute non-source (e.g., minimized or compacted) forms of - that code without the copy of the GNU LGPL normally required by - section 4, provided you include this license notice and a URL - through which recipients can access the Corresponding Source. - - @licend The above is the entire license notice - for the JavaScript code in this page. - */ - </script> -</head> -<body onload="signal_taler_wallet_onload()"> - - <header> - <div id="logo"> - <svg height="100" width="100"> - <circle cx="50" cy="50" r="40" stroke="darkcyan" stroke-width="6" fill="white" /> - <text x="19" y="82" font-family="Verdana" font-size="90" fill="darkcyan">B</text> - </svg> - </div> - - <h1 id="main-head">Blog - Fill out required information</h1> - </header> - - <aside class="sidebar" id="left"> - </aside> - - <section id="main"> - <article> - - <h1>Taler Not Installed</h1> - - <p> - Please proceede paying with your credit card, and fill the form - below. - </p> - - <form name="tform" action="" method="POST"> - First name <input type="text"></input><br> - Family name <input type="text"></input><br> - Age <input type="text"></input><br> - <input type="button" value="Ok"></input> - </form> - - </article> - </section> - -<script type="text/javascript"> - -/* This function is called from "taler_pay" after - we downloaded the JSON contract from the merchant. - We now need to pass it to the extension. */ -function handle_contract(json_contract) -{ - var cEvent = new CustomEvent('taler-contract', { detail: json_contract }); - - document.dispatchEvent(cEvent); -}; - - -/* Trigger Taler contract generation on the server, and pass the - contract to the extension once we got it. */ -function taler_pay(form) -{ - var contract_request = new XMLHttpRequest(); - - /* Note that the URL we give here is specific to the Demo-shop - and not required by the protocol: each web shop can - have its own way of generating and transmitting the - contract, there just must be a way to get the contract - and to pass it to the wallet when the user selects 'Pay'. */ - contract_request.open("GET", "essay_contract.php", true); - contract_request.onload = function (e) - { - if (contract_request.readyState == 4) - { - if (contract_request.status == 200) - { - /* display contract_requestificate (i.e. it sends the JSON string - to the extension) alert (contract_request.responseText); */ - console.log("contract here"); - console.log("response text:", contract_request.responseText); - handle_contract(contract_request.responseText); - } - else - { - /* There was an error obtaining the contract from the merchant, - obviously this should not happen. To keep it simple, we just - alert the user to the error. */ - alert("Failure to download contract from merchant " + - "(" + contract_request.status + "):\n" + - contract_request.responseText); - } - } - }; - contract_request.onerror = function (e) - { - /* There was an error obtaining the contract from the merchant, - obviously this should not happen. To keep it simple, we just - alert the user to the error. */ - alert("Failure requesting the contract:\n" + contract_request.statusText); - }; - contract_request.send(null); -} - - -/* This function is called when the user presses the - 'Ok' button. We are now supposed to trigger the - "corret" payment system logic. For this demo, we - only handle "taler". */ -function pay(form) -{ - for (var cnt=0; cnt < form.payment_system.length; cnt++) - { - var choice = form.payment_system[cnt]; - if (choice.checked) - { - if (choice.value == "taler") - { - taler_pay(form); - } - else - { - alert(choice.value + ": NOT available in this demo!"); - } - } - } -}; - - -/* The following event gets fired whenever a customer has a Taler - wallet installed in his browser. In that case, the webmaster can decide - whether or not to display/enable Taler as a payment option in the dialog. */ -function has_taler_wallet_cb(aEvent) -{ - console.log("has taler wallet"); - // make credit card form disappear - var cc = document.getElementById("main"); - var mainHead = document.getElementById("main-head") - mainHead.firstChild.nodeValue = "Processing payment..."; - cc.setAttribute("style", "display:none;"); - taler_pay(null); -}; - -/* Function called when the Taler extension was unloaded; - here we disable the Taler option and check "Lisa", as - some "valid" option should always be selected. */ -function taler_wallet_unload_cb(aEvent) -{ - var tbutton = document.getElementById("taler-radio-button-id"); - tbutton.setAttribute("disabled", "true"); - var lbutton = document.getElementById("lisa-radio-button-id"); - lbutton.setAttribute("checked", "true"); -}; - - -/* The merchant signals its taler-friendlyness to the wallet, - thereby causing the wallet to make itself more visible in the menu. - This function should be called both when the page is loaded - (i.e. via body's onload) and when we receive a "taler-load" signal - (as the extension may be loaded/enabled after the page was loaded) */ -function signal_taler_wallet_onload() -{ - var eve = new Event('taler-probe'); - document.dispatchEvent(eve); -}; - - -// function included to be run to test the page despite a -// wallet not being present in the browser. Enables the -// Taler option. NOT needed in real deployments. -function test_without_wallet(){ - var tbutton = document.getElementById("taler-radio-button-id"); - tbutton.removeAttribute("disabled"); -}; - - -// /////////////// Main logic run first //////////////////////// - -// Register event to be triggered by the wallet as a response to our -// first event -document.addEventListener("taler-wallet-present", - has_taler_wallet_cb, - false); - -// Register event to be triggered by the wallet when it gets enabled while -// the user is on the payment page -document.addEventListener("taler-load", - signal_taler_wallet_onload, - false); - -// Register event to be triggered by the wallet when it is unloaded -document.addEventListener("taler-unload", - taler_wallet_unload_cb, - false); -</script> -</body> -</html> diff --git a/src/frontend_blog/essay_contract.php b/src/frontend_blog/essay_contract.php @@ -28,27 +28,29 @@ if (null == $article){ // send contract $transaction_id = rand(0, 1001); -$p_id = hexdec(substr(sha1($article), -5)); - +//$p_id = hexdec(substr(sha1($article), -5)); +file_put_contents('/tmp/yyy', "bogus"); +file_put_contents('/tmp/yyy', $MERCHANT_CURRENCY); $now = new DateTime('now'); $teaser = get_teaser($article); $amount_value = 0; $amount_fraction = 50000; -$teatax = array ('value' => 1, - 'fraction' => 0, - 'currency' => $MERCHANT_CURRENCY); +$teatax = array (); $transaction_id = rand(0, 1001); -// Include all information so we can -// restore the contract without storing it + $fulfillment_url = url_rel("essay_fulfillment.php") - . '&uuid=${H_contract}'; -//file_put_contents("/tmp/debg1", $fulfillment_url); + . '&uuid=${H_contract}' + . '&timestamp=' . $now->getTimestamp() + . '&tid=' . $transaction_id; + +file_put_contents("/tmp/ffil", $fulfillment_url); $contract_json = generate_contract($amount_value, $amount_fraction, $MERCHANT_CURRENCY, $transaction_id, trim($teaser->nodeValue), - $p_id, + $article, + $article, $teatax, $now, $fulfillment_url); @@ -78,7 +80,6 @@ else $payments[$hc] = array( 'article' => $article, ); - - echo json_encode ($got_json, JSON_PRETTY_PRINT); + echo $resp->body->toString(); } ?> diff --git a/src/frontend_blog/essay_fulfillment.php b/src/frontend_blog/essay_fulfillment.php @@ -1,4 +1,19 @@ <!DOCTYPE html> +<!-- + This file is part of GNU TALER. + Copyright (C) 2014, 2015 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser 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, If not, see <http://www.gnu.org/licenses/> +--> <html lang="en"> <head> <title>Taler's "Demo" Shop</title> @@ -35,34 +50,10 @@ <section id="main"> <article> <?php -/* - This file is part of GNU TALER. - Copyright (C) 2014, 2015 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser 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, If not, see <http://www.gnu.org/licenses/> - */ - +// TODO return a mock CC payment page if no wallet in place include '../frontend_lib/util.php'; include './blog_lib.php'; - -$hc = get($_GET["uuid"]); - -if (empty($hc)) -{ - http_response_code(400); - echo "<p>Bad request (UUID missing)</p>"; - return; -} - +file_put_contents("/tmp/essayffil.dbg", "called"); $article = get($_GET["article"]); if (null == $article){ http_response_code(400); @@ -75,14 +66,27 @@ session_start(); $payments = get($_SESSION['payments'], array()); $my_payment = get($payments[$hc]); -// This will keep the query parameters, so the paying script -// can reconstruct the contract $pay_url = url_rel("essay_pay.php"); $offering_url = url_rel("essay_offer.php", true); $offering_url .= "?article=$article"; +file_put_contents("/tmp/ffilproc", $offering_url); if (true !== get($my_payment["is_payed"], false) || null === $my_payment) + { + $tid = get('tid'); + $timestamp = get('timestamp'); + // FIXME article name should be "melted" in the hash + // TODO reconstruct *here* the contract, hash it, and save it in the state + + if (null == $tid || null == $timestamp){ + // CC case + $_SESSION['cc_payment'] = true; + $cc_page = template("./essay_cc-payment.html", array('article' => $article)); + echo $cc_page; + die(); + + } echo "<p>Paying ... at $pay_url </p>"; echo "<script>executePayment('$hc', '$pay_url', '$offering_url');</script>"; return; diff --git a/src/frontend_blog/essay_offer.php b/src/frontend_blog/essay_offer.php @@ -6,15 +6,13 @@ include("../frontend_lib/merchants.php"); include("../frontend_lib/util.php"); include("./blog_lib.php"); - session_start(); $article = get($_GET['article']); if (null == $article){ echo "Please land here just to buy articles"; die(); } - echo "<h3>No Taler installed</h3>"; - echo "<p>activate it or pay by <a href='/cc_payment.php?article=$article'>credit card</a></p>"; - echo "<p id=article-name style='display: none;'>$article</input>"; + $cc_page = template("./essay_cc-payment.html", array('article' => $article)); + echo $cc_page; ?> </body> <script type="text/javascript"> @@ -54,7 +52,7 @@ function has_taler_wallet_cb(aEvent) { var article = document.getElementById('article-name'); - get_contract(article.firstChild.nodeValue); + get_contract(article.value); }; function signal_taler_wallet_onload() @@ -71,7 +69,7 @@ // the user is on the payment page document.addEventListener("taler-load", signal_taler_wallet_onload, - false); + false); </script> </html> diff --git a/src/frontend_blog/essay_pay.php b/src/frontend_blog/essay_pay.php @@ -16,10 +16,8 @@ */ /** - * This file should: - * 1. Check if the session is valid - * 2. augment the deposit permission with missing values - * 3. forward payment to backend + * TODO check the hashed contract in the state against the hashed contract + * actually bundled in the deposit permission */ include("../frontend_lib/merchants.php"); include("../frontend_lib/util.php"); @@ -36,8 +34,6 @@ if (empty($hc)) return; } -// TODO: check if contract body matches URL parameters, -// so we won't generate a response for the wrong receiver. $article = get($_GET["article"]); if (empty($article)) { diff --git a/src/frontend_lib/config.php b/src/frontend_lib/config.php @@ -1,12 +1,14 @@ <?php -$explicit_currency = false; -//$explicit_currency = "PUDOS"; +$REFUND_DELTA = 'P3M'; +// set to false when done with local tests +$explicit_currency = "PUDOS"; +$MERCHANT_CURRENCY = $explicit_currency; $host = $_SERVER["HTTP_HOST"]; switch ($host) { case "blog.demo.taler.net": -case "show.demo.taler.net": +case "shop.demo.taler.net": $MERCHANT_CURRENCY = "KUDOS"; break; case "blog.test.taler.net": @@ -14,12 +16,10 @@ case "shop.test.taler.net": $MERCHANT_CURRENCY = "PUDOS"; break; default: - if ($explicit_currency != false) - $MERCHANT_CURRENCY = $explicit_currency; - else { - http_response_code (500); - echo "<p>Bank configuration error: No currency for domain $host</p>\n"; - die(); + if(false == $explicit_currency){ + http_response_code (500); + echo "<p>Bank configuration error: No currency for domain $host</p>\n"; + die(); } } ?> diff --git a/src/frontend_lib/merchants.php b/src/frontend_lib/merchants.php @@ -11,9 +11,12 @@ function generate_contract($amount_value, $transaction_id, $desc, $p_id, - $teatax, + $corr_id, + $taxes, $now, $fulfillment_url){ + include("../frontend_lib/config.php"); + file_put_contents("/tmp/ddd", $REFUND_DELTA); $contract = array ('amount' => array ('value' => $amount_value, 'fraction' => $amount_fraction, 'currency' => $currency), @@ -28,13 +31,14 @@ function generate_contract($amount_value, 'fraction' => $amount_fraction, 'currency' => $currency), 'product_id' => $p_id, - 'taxes' => array (array ('teatax' => $teatax)), + 'taxes' => $taxes, 'delivery_date' => "Some Date Format", 'delivery_location' => 'LNAME1')), 'timestamp' => "/Date(" . $now->getTimestamp() . ")/", - 'fulfillment_url' => $fulfillment_url, 'expiry' => "/Date(" . $now->add(new DateInterval('P2W'))->getTimestamp() . ")/", - 'refund_deadline' => "/Date(" . $now->add(new DateInterval('P3M'))->getTimestamp() . ")/", + 'refund_deadline' => "/Date(" . $now->add(new DateInterval($REFUND_DELTA))->getTimestamp() . ")/", + 'repurchase_correlation_id' => $corr_id, + 'fulfillment_url' => $fulfillment_url, 'merchant' => array ('address' => 'LNAME2', 'name' => 'test merchant', 'jurisdiction' => 'LNAME3'), @@ -61,7 +65,7 @@ function generate_contract($amount_value, 'region' => 'Test Region', 'province' => 'Test Province', 'ZIP code' => 4908))); - $json = json_encode (array ('contract' => $contract, JSON_PRETTY_PRINT)); + $json = json_encode (array ('contract' => $contract), JSON_PRETTY_PRINT); return $json; } diff --git a/src/frontend_lib/util.php b/src/frontend_lib/util.php @@ -26,4 +26,22 @@ function url_rel($path, $strip=false) { $path, $strip); } + +function template($file, $array) { + if (file_exists($file)) { + $output = file_get_contents($file); + foreach ($array as $key => $val) { + $replace = '{'.$key.'}'; + $output = str_replace($replace, $val, $output); + } + return $output; + } +} + +function str_to_dom($str){ + $doc = new DOMDocument(); + $doc->loadHTML($str); + return $doc; + +} ?>