diff options
Diffstat (limited to 'src/frontend')
-rw-r--r-- | src/frontend/checkout.php | 136 | ||||
-rw-r--r-- | src/frontend/execute.js | 33 | ||||
-rw-r--r-- | src/frontend/execute.php | 56 | ||||
-rw-r--r-- | src/frontend/execute.tsx | 41 | ||||
-rw-r--r-- | src/frontend/fulfillment.php (renamed from src/frontend/fullfillment.php) | 48 | ||||
-rw-r--r-- | src/frontend/generate_taler_contract.php | 34 | ||||
-rw-r--r-- | src/frontend/index.html | 324 | ||||
-rw-r--r-- | src/frontend/pay.php | 85 | ||||
-rw-r--r-- | src/frontend/style.css | 123 |
9 files changed, 603 insertions, 277 deletions
diff --git a/src/frontend/checkout.php b/src/frontend/checkout.php index 157bd25f..21d4d8c4 100644 --- a/src/frontend/checkout.php +++ b/src/frontend/checkout.php @@ -1,7 +1,8 @@ <!DOCTYPE html> <html> <head> -<title>Taler's "Demo" Shop: Choose payment method</title> + <title>Toy Store - 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 @@ -31,7 +32,7 @@ </head> <body onload="signal_taler_wallet_onload()"> <!-- - This page's main aim is to show to the customer all the accepted + This main goal of this page is to show to the customer all the accepted payments methods and actually implementing just Taler; technically the steps are: @@ -50,52 +51,78 @@ $donation_currency = $_POST['donation_currency']; // get frational part - list ($donation_value, $donation_fraction) = split ("\.", $donation_amount, 2); + list ($donation_value, $donation_fraction) = explode (".", $donation_amount, 2); // create PHP session and store donation information in session $donation_fraction = (float) ("0." . $donation_fraction); session_start(); + session_unset(); $_SESSION['receiver'] = $donation_receiver; $_SESSION['amount_value'] = (int) $donation_amount; $_SESSION['amount_fraction'] = (int) ($donation_fraction * 1000000); $_SESSION['currency'] = $donation_currency; ?> -<h2>Select your payment option</h2> -<div> -This is an example for a "checkout" page of a Web shop. -On the previous page, you have created the shopping cart -and decided which product to buy (i.e. which project to -donate KUDOS to). Now in this page, you are asked to -select a payment option. As Taler is not yet universally -used, we expect merchants will offer various payment options. -<p> -The page also demonstrates how to only enable (or show) the Taler -option if Taler is actually supported by the browser. For example, -if you disable the Taler extension now, the Taler payment option -will be disabled in the page. Naturally, you could also trivially -hide the Taler option entirely by changing the visibility instead. -<p> -Note that you MUST select Taler here for the demo to continue, -as the other payment options are just placeholders and not -really working in the demonstration. Also, it is of course -possible to ask the user to make this choice already on the -previous page (with the shopping cart), we just separated the -two steps to keep each step as simple as possible. -</div> -<form name="tform" action="" method="POST"> - <div id="opt-form" align="left"><br> - <input type="radio" name="payment_system" value="lisa" - id="lisa-radio-button-id">Lisa</input> - <br> - <input type="radio" name="payment_system" value="ycard">You Card</input> - <br> - <input type="radio" name="payment_system" value="cardme">Card Me</input> - <br> - <input type="radio" name="payment_system" value="taler" - id="taler-radio-button-id" disabled="true">Taler</input> - <br> - <input type="button" onclick="pay(this.form)" value="Ok"> - </div> -</form> + + <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">S</text> + </svg> + </div> + + <h1>Toy Store - Select payment method</h1> + </header> + + <aside class="sidebar" id="left"> + </aside> + + <section id="main"> + <article> + + <h1>Select your payment method</h1> + + <p> + This is an example for a "checkout" page of a Web shop. + On the previous page, you have created the shopping cart + and decided which product to buy (i.e. which project to + donate KUDOS to). Now in this page, you are asked to + select a payment option. As Taler is not yet universally + used, we expect merchants will offer various payment options. + </p> + <p> + The page also demonstrates how to only enable (or show) the Taler + option if Taler is actually supported by the browser. For example, + if you disable the Taler extension now, the Taler payment option + will be disabled in the page. Naturally, you could also trivially + hide the Taler option entirely by changing the visibility instead. + </p> + <p> + Note that you MUST select Taler here for the demo to continue, + as the other payment options are just placeholders and not + really working in the demonstration. Also, it is of course + possible to ask the user to make this choice already on the + previous page (with the shopping cart), we just separated the + two steps to keep each step as simple as possible. + </p> + + <form name="tform" action="" method="POST"> + <div id="opt-form" align="left"><br> + <input type="radio" name="payment_system" value="lisa" + id="lisa-radio-button-id">Lisa</input> + <br/> + <input type="radio" name="payment_system" value="ycard">You Card</input> + <br/> + <input type="radio" name="payment_system" value="cardme">Card Me</input> + <br/> + <input type="radio" name="payment_system" value="taler" + id="taler-radio-button-id" disabled="true">Taler</input> + <br/> + <input type="button" onclick="pay(this.form)" value="Ok"></input> + </div> + </form> + + </article> + </section> <script type="text/javascript"> @@ -106,7 +133,7 @@ function handle_contract(json_contract) { var cEvent = new CustomEvent('taler-contract', { detail: json_contract }); - document.body.dispatchEvent(cEvent); + document.dispatchEvent(cEvent); }; @@ -121,7 +148,7 @@ function taler_pay(form) 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", "/generate_taler_contract.php", true); + contract_request.open("GET", "generate_taler_contract.php", true); contract_request.onload = function (e) { if (contract_request.readyState == 4) @@ -129,9 +156,9 @@ function taler_pay(form) if (contract_request.status == 200) { /* display contract_requestificate (i.e. it sends the JSON string - to the extension) alert (contract_request.responseText); */ + to the extension) alert (contract_request.responseText); */ + console.log("response text:", contract_request.responseText); handle_contract(contract_request.responseText); - } else { @@ -211,7 +238,7 @@ function taler_wallet_unload_cb(aEvent) function signal_taler_wallet_onload() { var eve = new Event('taler-checkout-probe'); - document.body.dispatchEvent(eve); + document.dispatchEvent(eve); }; @@ -228,21 +255,20 @@ function test_without_wallet(){ // Register event to be triggered by the wallet as a response to our // first event -document.body.addEventListener("taler-wallet-present", - has_taler_wallet_cb, - false); +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.body.addEventListener("taler-load", - signal_taler_wallet_onload, - false); +document.addEventListener("taler-load", + signal_taler_wallet_onload, + false); // Register event to be triggered by the wallet when it is unloaded -document.body.addEventListener("taler-unload", - taler_wallet_unload_cb, - false); - +document.addEventListener("taler-unload", + taler_wallet_unload_cb, + false); </script> </body> </html> diff --git a/src/frontend/execute.js b/src/frontend/execute.js new file mode 100644 index 00000000..a9045cb5 --- /dev/null +++ b/src/frontend/execute.js @@ -0,0 +1,33 @@ +"use strict"; +// JSX literals are compiled to calls to React.createElement calls. +let React = { + createElement: function (tag, props, ...children) { + let e = document.createElement(tag); + for (let k in props) { + e.setAttribute(k, props[k]); + } + for (let child of children) { + if ("string" === typeof child || "number" == typeof child) { + child = document.createTextNode(child); + } + e.appendChild(child); + } + return e; + } +}; +document.addEventListener("DOMContentLoaded", function (e) { + var eve = new CustomEvent('taler-execute-payment', { detail: { H_contract: h_contract } }); + document.dispatchEvent(eve); +}); +function replace(el, r) { + el.parentNode.replaceChild(r, el); +} +document.addEventListener("taler-payment-result", function (e) { + if (!e.detail.success) { + alert("Payment failed\n" + JSON.stringify(e.detail)); + return; + } + console.log("finished payment"); + let msg = React.createElement("div", null, "Payment successful. View your ", React.createElement("a", {"href": e.detail.fulfillmentUrl}, "product"), "."); + replace(document.getElementById("loading"), msg); +}); diff --git a/src/frontend/execute.php b/src/frontend/execute.php new file mode 100644 index 00000000..33021fd3 --- /dev/null +++ b/src/frontend/execute.php @@ -0,0 +1,56 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <title>Toy Store - 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) 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 2.1 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 2.1 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> + <script type="text/javascript"> +<?php +session_start(); +echo "var h_contract=\"$_SESSION[H_contract]\";\n"; +?> + </script> + <script type="text/javascript" src="execute.js"></script> +</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">S</text> + </svg> + </div> + <h1>Toy Store - Taler Demo</h1> + </header> + + <aside class="sidebar" id="left"> + </aside> + + <section id="main"> + <h1>Executing Payment ...</h1> + <div id="loading">Loading...</div> +</body> +</html> diff --git a/src/frontend/execute.tsx b/src/frontend/execute.tsx new file mode 100644 index 00000000..67cf8e06 --- /dev/null +++ b/src/frontend/execute.tsx @@ -0,0 +1,41 @@ +"use strict"; + + +// JSX literals are compiled to calls to React.createElement calls. +let React = { + createElement: function(tag, props, ...children) { + let e = document.createElement(tag); + for (let k in props) { + e.setAttribute(k, props[k]); + } + for (let child of children) { + if ("string" === typeof child || "number" == typeof child) { + child = document.createTextNode(child); + } + e.appendChild(child); + } + return e; + } +}; + +declare var h_contract: string; + +document.addEventListener("DOMContentLoaded", function (e) { + var eve = new CustomEvent('taler-execute-payment', {detail: {H_contract: h_contract}}); + document.dispatchEvent(eve); +}); + +function replace(el, r) { + el.parentNode.replaceChild(r, el); +} + +document.addEventListener("taler-payment-result", function (e: CustomEvent) { + if (!e.detail.success) { + alert("Payment failed\n" + JSON.stringify(e.detail)); + return; + } + console.log("finished payment"); + let msg = + <div>Payment successful. View your <a href={e.detail.fulfillmentUrl}>product</a>.</div>; + replace(document.getElementById("loading"), msg); +}); diff --git a/src/frontend/fullfillment.php b/src/frontend/fulfillment.php index d7677aa7..32f3c0cd 100644 --- a/src/frontend/fullfillment.php +++ b/src/frontend/fulfillment.php @@ -6,7 +6,23 @@ </head> <body> -<?php + <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">S</text> + </svg> + </div> + + <h1>Toy Store - Payment succeeded</h1> + </header> + + <aside class="sidebar" id="left"> + </aside> + + <section id="main"> + <article> +<?php /* This file is part of GNU TALER. Copyright (C) 2014, 2015 GNUnet e.V. @@ -27,6 +43,13 @@ $cli_debug = false; $backend_test = true; +function generate_msg ($link){ + $msg = "<p>Thanks for donating to " . $_SESSION['receiver'] . ".</p>"; + if (false != $link) + $msg .= "<p>Check our latest <a href=\"" . $link . "\">news!</a></p>"; + return $msg; +} + if ($_GET['cli_debug'] == 'yes') $cli_debug = true; @@ -38,13 +61,26 @@ if ($_GET['backend_test'] == 'no') session_start(); - if (! isset ($_SESSION['payment_ok'])) - echo "Please land here after a successful payment!"; -else - echo "Thanks for donating to " . $_SESSION['receiver']; + echo "<p>Please land here after a successful payment!</p>"; +else{ + $news = false; + switch ($_SESSION['receiver']){ + case "Taler": + $news = "https://taler.net/news"; + break; + case "GNUnet": + $news = "https://gnunet.org/"; + break; + case "Tor": + $news = "https://www.torproject.org/press/press.html.en"; + break; + } + echo generate_msg ($news); +} ?> - + </article> + </section> </body> </html> diff --git a/src/frontend/generate_taler_contract.php b/src/frontend/generate_taler_contract.php index c71542c8..14add359 100644 --- a/src/frontend/generate_taler_contract.php +++ b/src/frontend/generate_taler_contract.php @@ -35,10 +35,10 @@ $cli_debug = false; $backend_test = true; -if ($_GET['cli_debug'] == 'yes') +if (isset($_GET['cli_debug']) && $_GET['cli_debug'] == 'yes') $cli_debug = true; -if ($_GET['backend_test'] == 'no') +if (isset($_GET['backend_test']) && $_GET['backend_test'] == 'no') { $cli_debug = true; $backend_test = false; @@ -90,9 +90,12 @@ $teatax = array ('value' => 1, // Take a timestamp $now = new DateTime('now'); +$PAY_URL = "pay.php"; +$EXEC_URL = "execute.php"; + // pack the JSON for the contract // --- FIXME: exact format needs review! -$json = json_encode (array ('amount' => array ('value' => $amount_value, +$contract = array ('amount' => array ('value' => $amount_value, 'fraction' => $amount_fraction, 'currency' => $currency), 'max_fee' => array ('value' => 3, @@ -110,7 +113,8 @@ $json = json_encode (array ('amount' => array ('value' => $amount_value, 'delivery_date' => "Some Date Format", 'delivery_location' => 'LNAME1')), 'timestamp' => "/Date(" . $now->getTimestamp() . ")/", - 'pay_url' => "/taler/pay", + 'pay_url' => $PAY_URL, + 'exec_url' => $EXEC_URL, 'expiry' => "/Date(" . $now->add(new DateInterval('P2W'))->getTimestamp() . ")/", 'refund_deadline' => "/Date(" . $now->add(new DateInterval('P3M'))->getTimestamp() . ")/", 'merchant' => array ('address' => 'LNAME2', @@ -138,19 +142,22 @@ $json = json_encode (array ('amount' => array ('value' => $amount_value, 'state' => 'Test State', 'region' => 'Test Region', 'province' => 'Test Province', - 'ZIP code' => 4908))), JSON_PRETTY_PRINT); + 'ZIP code' => 4908))); +$json = json_encode (array ('contract' => $contract, 'exec_url' => $EXEC_URL, 'pay_url' => $PAY_URL), JSON_PRETTY_PRINT); if ($cli_debug && !$backend_test) { echo $json . "\n"; exit; } -// Craft the HTTP request, note that the backend -// could be on an entirely different machine if -// desired. -$req = new http\Client\Request ("POST", - "http://" . $_SERVER["SERVER_NAME"] . "/backend/contract", - array ("Content-Type" => "application/json")); + +$url = (new http\URL("http://".$_SERVER["HTTP_HOST"])) + ->mod(array ("path" => "backend/contract"), http\Url::JOIN_PATH); + +$req = new http\Client\Request("POST", + $url, + array ("Content-Type" => "application/json")); + $req->getBody()->append ($json); // Execute the HTTP request @@ -168,10 +175,11 @@ http_response_code ($status_code); if ($status_code != 200) { echo "Error while generating the contract"; + echo $resp->body->toString (); } else -{ - // send the contract back to the wallet without touching it +{ $got_json = json_decode ($resp->body->toString ()); + $_SESSION['H_contract'] = $got_json->H_contract; echo $resp->body->toString (); } ?> diff --git a/src/frontend/index.html b/src/frontend/index.html index 8111735f..21ca0d65 100644 --- a/src/frontend/index.html +++ b/src/frontend/index.html @@ -1,36 +1,83 @@ <!DOCTYPE html> <html lang="en"> <head> - <title>Taler's "Demo" Shop</title> + <title>Toy "Store" - 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) 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 2.1 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 2.1 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> + <script type="text/javascript"> + /* @licstart The following is the entire license notice for the + JavaScript code in this page. + + Copyright (C) 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 2.1 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 2.1 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. + */ + function handleInstall() { + var b = document.getElementById("main"); + b.classList.add("installed"); + }; + + function handleUninstall() { + var b = document.getElementById("main"); + b.classList.remove("installed"); + }; + + function probeTaler() { + var eve = new Event("taler-probe"); + document.dispatchEvent(eve); + } + + + // Only probe taler once the DOM is ready and + // we can manipulate it. + window.addEventListener("load", probeTaler, false); + + document.addEventListener("taler-wallet-present", handleInstall, false); + document.addEventListener("taler-unload", handleUninstall, false); + document.addEventListener("taler-load", handleInstall, false); + + </script> + <style> + *:not(.installed) .if-installed { display: none } + .installed .if-not-installed { display: none } + *:not(.installed) .if-not-installed { display: initial } + .installed .if-installed { display: initial } + </style> </head> -<body id="css-zen-garden" onload="signal_me()"> - <div class="supporting" id="welcome" role="main"> - <div class="explanation" id="zen-explanation" role="article"> - <h1>Welcome to the Taler "Demo" Shop</h1> + +<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">S</text> + </svg> + </div> + + <h1>Toy "Store" - Taler Demo</h1> + </header> + + <aside class="sidebar" id="left"> + </aside> + + <section id="main"> + <article> + <h1>Welcome to the Taler Demo Shop</h1> + <p>This "toy" website provides you with the ability to experience using the <a href="https://www.taler.net/">GNU Taler</a> @@ -45,152 +92,93 @@ <tt>mint.demo.taler.net</tt> and <tt>bank.demo.taler.net</tt>, correspond to a Taler mint and bank with tight Taler integration respectively. - <!-- TODO: maybe offer the wallet at 'taler.net/extension' in the - future, instead of at 'demo.taler.net/'? --> - </p> - </div> - </div> - <div class="supporting" id="instructions" role="main"> - <div class="explanation" id="installation" role="article"> - <h2>Step 1: Installing the Taler wallet (once)</h2> - <p>First, you need to install the Taler wallet browser extension. - It is currently only available for Firefox. If you run - Firefox, simply click <a href="http://demo.taler.net/extension">here</a> - to download and install the extension. You will then have to - click on "allow" and "install" dialogs shown by Firefox. - After that, the Taler logo should appear on the right side - of your navigation bar. - <!-- TODO: insert screenshot highlighting the icon? --> - </p> - </div> - <div class="explanation" id="installation-done" role="article" style="display:none;"> - <h2>Step 1: Installing the Taler wallet (done!)</h2> - <p>Congratulations, you have installed the Taler wallet correctly. - You can now proceed with the next steps. </p> - </div> - <div class="explanation" id="wire" role="article" style="display:none;"> - <h2>Step 2: Withdraw coins (occasionally)</h2> - <p>The next step is to withdraw coins, after all you cannot - pay with an empty wallet. To be allowed to withdraw - coins from a mint, you first need to transfer currency to the mint - using the normal banking system, for example by using a - wire transfer. If the bank offers a tight integration with Taler, it - may also support this directly over the home banking online interface. - <br> - For the demonstration, we have created a "bank" that - allows you to "wire" funds (in KUDOS) to the mint simply by - filling in the desired amount into a form. Naturally, when - using a real bank with real money, you would have to authenticate - and authorize the transfer. - <br> - Note that you would not do this step for each purchase or each shop. - Payment with Taler is like paying - with cash: you withdraw currency at the bank (or an ATM) and then - pay at many merchants without having to authenticate each time. - <br> - So, unless you have already done so, please go ahead and withdraw - KUDOS at the - <a href="http://bank.demo.taler.net/" target="_blank">Demo bank</a> - (opens in a new tab).</p> - </p> - </div> - <div class="explanation" id="payment" role="article" style="display:none;"> - <h2>Step 3: Shop! (as long as you have KUDOS left in the wallet)</h2> - <p>Now it is time to spend your hard earned KUDOS. - Note that we cannot really tell if you got any yet, - as your Taler wallet balance is visible to you, but - of course is hidden entirely from the shop.</p> - <p>The form that follows corresponds to the shopping - cart of a real Web shop; however, we kept it - very simple for the demonstration.</p> - <p>So, please choose a project and the amount of KUDOS you - wish to donate:</p> - <form name="tform" action="/checkout.php" method="POST"> - <div class="participation" id="fake-shop"> - <br> - <input type="radio" name="donation_receiver" value="Taler" checked="true">GNU Taler</input> - <br> - <input type="radio" name="donation_receiver" value="Tor">Tor</input> - <br> - <input type="radio" name="donation_receiver" value="GNUnet">GNUnet</input> + </article> + + <section> + + <article> + <h2>Step 1: Installing the Taler wallet</h2> + <p class="if-not-installed"> + First, you need to <a href="http://demo.taler.net/">install</a> + the Taler wallet browser extension. + </p> + <p class="if-installed"> + Congratulations, you have installed the Taler wallet correctly. + You can now proceed with the next steps. + </p> + </article> + + <article class="if-installed"> + <h2>Step 2: Withdraw coins <sup>(occasionally)</sup></h2> + + <p>The next step is to withdraw coins, after all you cannot + pay with an empty wallet. To be allowed to withdraw + coins from a mint, you first need to transfer currency to the mint + using the normal banking system, for example by using a + wire transfer. If the bank offers a tight integration with Taler, it + may also support this directly over the home banking online interface. <br> - <select id="taler-donation" name="donation_amount"> - <option value="0.1">0.1 KUDOS</option> - <option value="1.0">1 KUDOS</option> - <option value="6.0">5 KUDOS (*)</option> - <option value="10.0">10 KUDOS</option> - </select> - <input type="hidden" name="donation_currency" value="KUDOS"/> - <input type="submit" name="keyName" value="Donate!"/> + For the demonstration, we have created a "bank" that + allows you to "wire" funds (in KUDOS) to the mint simply by + filling in the desired amount into a form. Naturally, when + using a real bank with real money, you would have to authenticate + and authorize the transfer. <br> + Note that you would not do this step for each purchase or each shop. + Payment with Taler is like paying + with cash: you withdraw currency at the bank (or an ATM) and then + pay at many merchants without having to authenticate each time. <br> - </div> - </form> - <p>(*) To make it a bit more fun, the 5 KUDOS option - is deliberately implemented with a fault: the merchant will try to - make you donate 6 KUDOS instead of the 5 KUDOS you got to see. But do - not worry, you will be given the opportunity to review the - final offer from the merchant in a window secured - by the Taler extension. That way, you can spot the - error before committing to an incorrect contract.</p> - </p> - </div> - </div> - <script type="text/javascript"> - /* This function is called if/when a Wallet is installed. - It should enable the parts of the page that only make - sense after the Wallet has been loaded. - */ - function wallet_installed_cb(){ - b = document.getElementById("installation"); - b.style.display = 'none'; - b = document.getElementById("installation-done"); - b.style.display = ''; - b = document.getElementById("wire"); - b.style.display = ''; - b = document.getElementById("payment"); - b.style.display = ''; - }; + So, unless you have already done so, please go ahead and withdraw + KUDOS at the + <a href="http://bank.demo.taler.net/" target="_blank">Demo bank</a> + (opens in a new tab).</p> + </article> - function wallet_uninstalled_cb(){ - b = document.getElementById("installation"); - b.style.display = ''; - b = document.getElementById("installation-done"); - b.style.display = 'none'; - b = document.getElementById("wire"); - b.style.display = 'none'; - b = document.getElementById("payment"); - b.style.display = 'none'; - }; + <article class="if-installed"> + <h2>Step 3: Shop! <sup>(as long as you have KUDOS left)</sup></h2> - /* The merchant signals its taler-friendlyness to the client */ - function signal_me() - { - var eve = new Event('taler-checkout-probe'); - document.body.dispatchEvent(eve); - //alert("signaling"); - }; + <p>Now it is time to spend your hard earned KUDOS. + Note that we cannot really tell if you got any yet, + as your Taler wallet balance is visible to you, but + of course is hidden entirely from the shop.</p> + <p>The form that follows corresponds to the shopping + cart of a real Web shop; however, we kept it + very simple for the demonstration.</p> + <p>So, please choose a project and the amount of KUDOS you + wish to donate:</p> - function test_without_wallet(){ - wallet_installed_cb(); - } - - document.body.addEventListener("taler-unload", - wallet_uninstalled_cb, - false, false); - - /* Set up a listener to be called whenever a Wallet gets installed - so that the user is led towards the demo's steps progressively */ - document.body.addEventListener("taler-wallet-present", - wallet_installed_cb, - false, false); - - /* Setup callback to be called whenever the wallet is loaded/enabled - while the browser is already on this page */ - document.body.addEventListener("taler-load", - signal_me, - false); - </script> + <form name="tform" action="checkout.php" method="POST"> + <div class="participation" id="fake-shop"> + <br> + <input type="radio" name="donation_receiver" value="Taler" checked="true">GNU Taler</input> + <br> + <input type="radio" name="donation_receiver" value="Tor">Tor</input> + <br> + <input type="radio" name="donation_receiver" value="GNUnet">GNUnet</input> + <br> + <select id="taler-donation" name="donation_amount"> + <option value="0.1">0.1 KUDOS</option> + <option value="1.0">1 KUDOS</option> + <option value="6.0">5 KUDOS (*)</option> + <option value="10.0">10 KUDOS</option> + </select> + <input type="hidden" name="donation_currency" value="KUDOS"/> + <input type="submit" name="keyName" value="Donate!"/> + <br> + <br> + </div> + </form> + <p>(*) To make it a bit more fun, the 5 KUDOS option + is deliberately implemented with a fault: the merchant will try to + make you donate 6 KUDOS instead of the 5 KUDOS you got to see. But do + not worry, you will be given the opportunity to review the + final offer from the merchant in a window secured + by the Taler extension. That way, you can spot the + error before committing to an incorrect contract.</p> + </article> + </section> + </section> </body> </html> diff --git a/src/frontend/pay.php b/src/frontend/pay.php index 97ee5290..bf0be438 100644 --- a/src/frontend/pay.php +++ b/src/frontend/pay.php @@ -23,39 +23,39 @@ NOTE: 'max_fee' must be consistent with the same value indicated within the contract; thus, a "real" merchant must implement such a mapping -*/ + */ + +session_start(); $cli_debug = false; $backend_test = true; -if ($_GET['cli_debug'] == 'yes') +if (isset($_GET['cli_debug']) && $_GET['cli_debug'] == 'yes') +{ $cli_debug = true; +} -if ($_GET['backend_test'] == 'no') +if (isset($_GET['backend_test']) && $_GET['backend_test'] == 'no') { $cli_debug = true; $backend_test = false; } -session_start(); - -if (!$cli_debug && (! isset($_SESSION['receiver']))) +if (!isset($_SESSION['H_contract'])) { - http_response_code(400); - echo "Please, donate to someone before landing here!"; - exit(); + echo "No session active."; + http_response_code (301); + return; } -$cli_debug = false; -$backend_test = true; - -if ($_GET['cli_debug'] == 'yes') - $cli_debug = true; - -if ($_GET['backend_test'] == 'no') +if (isset($_SESSION['payment_ok']) && $_SESSION['payment_ok'] == true) { - $cli_debug = true; - $backend_test = false; + $_SESSION['payment_ok'] = true; + http_response_code (301); + $url = (new http\URL($_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'])) + ->mod(array ("path" => "fulfillment.php"), http\Url::JOIN_PATH); + header("Location: $url"); + die(); } $post_body = file_get_contents('php://input'); @@ -66,15 +66,15 @@ $edate = array ('edate' => $deposit_permission = json_decode ($post_body, true); -$to_add = array ('max_fee' => array ('value' => 3, - 'fraction' => 8, - 'currency' => $_SESSION['currency']), - 'amount' => array ('value' => $_SESSION['amount_value'], - 'fraction' => $_SESSION['amount_fraction'], - 'currency' => $_SESSION['currency'])); +$to_add = array('max_fee' => array('value' => 3, + 'fraction' => 8, + 'currency' => $_SESSION['currency']), + 'amount' => array('value' => $_SESSION['amount_value'], + 'fraction' => $_SESSION['amount_fraction'], + 'currency' => $_SESSION['currency'])); -$new_deposit_permission = array_merge ($deposit_permission, $to_add); -$new_deposit_permission_edate = array_merge ($new_deposit_permission, $edate); +$new_deposit_permission = array_merge($deposit_permission, $to_add); +$new_deposit_permission_edate = array_merge($new_deposit_permission, $edate); /* Craft the HTTP request, note that the backend could be on an entirely different machine if @@ -85,14 +85,25 @@ if ($cli_debug && !$backend_test) /* DO NOTE the newline at the end of 'echo's argument */ //echo json_encode ($new_deposit_permission_edate, JSON_PRETTY_PRINT) - echo json_encode ($new_deposit_permission, JSON_PRETTY_PRINT) + echo json_encode($new_deposit_permission, JSON_PRETTY_PRINT) . "\n"; exit; } -$req = new http\Client\Request ("POST", - "http://" . $_SERVER["SERVER_NAME"] . "/backend/pay", - array ("Content-Type" => "application/json")); + +// Backend is relative to the shop site. +/** + * WARNING: the "shop site" is '"http://".$_SERVER["HTTP_HOST"]' + * So do not attach $_SERVER["REQUEST_URI"] before proxying requests + * to the backend + */ +//$url = (new http\URL("http://".$_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"])) +$url = (new http\URL("http://".$_SERVER["HTTP_HOST"])) + ->mod(array ("path" => "backend/pay"), http\Url::JOIN_PATH); + +$req = new http\Client\Request("POST", + $url, + array ("Content-Type" => "application/json")); $req->getBody()->append (json_encode ($new_deposit_permission)); // Execute the HTTP request @@ -112,15 +123,19 @@ if ($status_code != 200) /* error: just forwarding to the wallet what gotten from the backend (which is forwarding 'as is' the error gotten from the mint) */ + echo json_encode ($new_deposit_permission); + echo "Error came from the backend, status $status_code\n"; + echo "\n"; echo $resp->body->toString (); - } else { -$_SESSION['payment_ok'] = true; -http_response_code (301); -header("Location: http://" . $_SERVER["SERVER_NAME"] . "/fullfillment"); -die(); + $_SESSION['payment_ok'] = true; + http_response_code (301); + $url = (new http\URL($_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'])) + ->mod(array ("path" => "fulfillment.php"), http\Url::JOIN_PATH); + header("Location: $url"); + die(); } ?> diff --git a/src/frontend/style.css b/src/frontend/style.css index e69de29b..c2cc51ee 100644 --- a/src/frontend/style.css +++ b/src/frontend/style.css @@ -0,0 +1,123 @@ +body { + background-color: white; + margin: 0; + padding: 0; + font-family: Verdana, sans; +} + +header { + width: 100%; + height: 100px; + margin: 0; + padding: 0; + border-bottom: 1px solid black; +} + +header h1 { + font-size: 200%; + margin: 0; + padding: 0 0 0 120px; + position: relative; + top: 50%; + transform: translateY(-50%); +} + +header #logo { + float: left; + width: 100px; + padding: 0; + margin: 0; + text-align: center; + border-right: 1px solid black; +} + +aside { + width: 100px; + float: left; +} + +section#main { + margin: 0 0 0 100px; + padding: 20px; + border-left: 1px solid black; + height: 100%; + max-width: 40em; +} + +section#main h1:first-child { + margin-top: 0; +} + +h1 { + font-size: 160%; +} + +h2 { + font-size: 140%; +} + +h3 { + font-size: 120%; +} + +h4, h5, h6 { + font-size: 100%; +} + +.loader { + font-size: 10px; + margin: 50px auto; + text-indent: -9999em; + width: 11em; + height: 11em; + border-radius: 50%; + background: #ffffff; + background: -moz-linear-gradient(left, #000 10%, rgba(255, 255, 255, 0) 42%); + background: -webkit-linear-gradient(left, #000 10%, rgba(255, 255, 255, 0) 42%); + background: -o-linear-gradient(left, #000 10%, rgba(255, 255, 255, 0) 42%); + background: -ms-linear-gradient(left, #000 10%, rgba(255, 255, 255, 0) 42%); + position: relative; + -webkit-animation: load3 1.4s infinite linear; + animation: load3 1.4s infinite linear; + -webkit-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); +} + +.loader:after { + background: #fff; + width: 75%; + height: 75%; + border-radius: 50%; + content: ''; + margin: auto; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; +} + +@-webkit-keyframes load3 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes load3 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + + |