aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2016-09-08 17:26:31 +0200
committerFlorian Dold <florian.dold@gmail.com>2016-09-08 17:26:31 +0200
commita164ea91838b0dd2506acbd67e1b3720abaa7e01 (patch)
tree93b698668cffcc93c2ba3294ff8845dd4d42e439
parent4b67f220e7d9ab4a7d7a190892f028995baa9902 (diff)
rudimentary 402 handling
-rw-r--r--content_scripts/notify.ts146
-rw-r--r--lib/wallet/wallet.ts7
-rw-r--r--lib/wallet/wxMessaging.ts33
-rw-r--r--pages/execute-payment.html80
-rw-r--r--pages/offer-contract-from.html80
-rw-r--r--pages/offer-contract-from.tsx30
-rw-r--r--tsconfig.json1
7 files changed, 170 insertions, 207 deletions
diff --git a/content_scripts/notify.ts b/content_scripts/notify.ts
index 54d7b6acb..ad77a1e37 100644
--- a/content_scripts/notify.ts
+++ b/content_scripts/notify.ts
@@ -31,7 +31,135 @@
namespace TalerNotify {
const PROTOCOL_VERSION = 1;
- console.log("Taler injected", chrome.runtime.id);
+ /**
+ * Wallet-internal version of offerContractFrom, used for 402 payments.
+ */
+ function internalOfferContractFrom(url: string) {
+ function handle_contract(contract_wrapper) {
+ var cEvent = new CustomEvent("taler-confirm-contract", {
+ detail: {
+ contract_wrapper: contract_wrapper,
+ replace_navigation: true
+ }
+ });
+ document.dispatchEvent(cEvent);
+ }
+
+ var contract_request = new XMLHttpRequest();
+ console.log("downloading contract from '" + url + "'")
+ contract_request.open("GET", url, true);
+ contract_request.onload = function (e) {
+ if (contract_request.readyState == 4) {
+ if (contract_request.status == 200) {
+ console.log("response text:",
+ contract_request.responseText);
+ var contract_wrapper = JSON.parse(contract_request.responseText);
+ if (!contract_wrapper) {
+ console.error("response text was invalid json");
+ alert("Failure to download contract (invalid json)");
+ return;
+ }
+ handle_contract(contract_wrapper);
+ } else {
+ alert("Failure to download contract from merchant " +
+ "(" + contract_request.status + "):\n" +
+ contract_request.responseText);
+ }
+ }
+ };
+ contract_request.onerror = function (e) {
+ alert("Failure requesting the contract:\n"
+ + contract_request.statusText);
+ };
+ contract_request.send();
+ }
+
+ /**
+ * Wallet-internal version of executeContract, used for 402 payments.
+ */
+ function internalExecuteContract(contractHash: string, payUrl: string,
+ offerUrl: string) {
+ /**
+ * Handle a failed payment.
+ *
+ * Try to notify the wallet first, before we show a potentially
+ * synchronous error message (such as an alert) or leave the page.
+ */
+ function handleFailedPayment(status) {
+ let timeoutHandle = null;
+ function err() {
+ alert("Payment failed: Unexpected status code for $pay_url: " + status);
+ }
+ function onResp() {
+ if (timeoutHandle != null) {
+ clearTimeout(timeoutHandle);
+ timeoutHandle = null;
+ }
+ err();
+ }
+ function onTimeout() {
+ timeoutHandle = null;
+ err();
+ }
+ let eve = new CustomEvent('taler-payment-failed', {detail: {}});
+ document.dispatchEvent(eve);
+ document.addEventListener("taler-payment-failed-ok", onResp, false);
+ timeoutHandle = setTimeout(onTimeout, 200);
+ }
+
+
+ function handleResponse(evt) {
+ console.log("handling taler-notify-payment");
+ // Payment timeout in ms.
+ let timeout_ms = 1000;
+ // Current request.
+ let r;
+ let timeoutHandle = null;
+ function sendPay() {
+ r = new XMLHttpRequest();
+ r.open("post", payUrl);
+ r.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
+ r.send(JSON.stringify(evt.detail.payment));
+ r.onload = function() {
+ switch (r.status) {
+ case 200:
+ window.location.href = subst(evt.detail.contract.fulfillment_url,
+ evt.detail.H_contract);
+ window.location.reload(true);
+ break;
+ default:
+ handleFailedPayment(r.status);
+ break;
+ }
+ r = null;
+ if (timeoutHandle != null) {
+ clearTimeout(timeoutHandle);
+ timeoutHandle = null;
+ }
+ };
+ function retry() {
+ if (r) {
+ r.abort();
+ r = null;
+ }
+ timeout_ms = Math.min(timeout_ms * 2, 10 * 1000);
+ console.log("sendPay timed out, retrying in ", timeout_ms, "ms");
+ sendPay();
+ }
+ timeoutHandle = setTimeout(retry, timeout_ms);
+ }
+ sendPay();
+ }
+
+ let detail = {
+ H_contract: contractHash,
+ offering_url: offerUrl
+ };
+
+ document.addEventListener("taler-notify-payment", handleResponse, false);
+ let eve = new CustomEvent('taler-fetch-payment', {detail: detail});
+ document.dispatchEvent(eve);
+ }
function subst(url: string, H_contract) {
url = url.replace("${H_contract}", H_contract);
@@ -42,13 +170,12 @@ namespace TalerNotify {
const handlers = [];
function init() {
- chrome.runtime.sendMessage({type: "ping"}, () => {
+ chrome.runtime.sendMessage({type: "ping"}, (resp) => {
if (chrome.runtime.lastError) {
console.log("extension not yet ready");
window.setTimeout(init, 200);
return;
}
- console.log("got pong");
registerHandlers();
// Hack to know when the extension is unloaded
let port = chrome.runtime.connect();
@@ -59,6 +186,19 @@ namespace TalerNotify {
document.removeEventListener(handler.type, handler.listener);
}
});
+
+ console.log(resp);
+
+ if (resp.type === "fetch") {
+ console.log("it's fetch");
+ internalOfferContractFrom(resp.contractUrl);
+ document.documentElement.style.visibility = "hidden";
+
+ } else if (resp.type === "execute") {
+ console.log("it's execute");
+ document.documentElement.style.visibility = "hidden";
+ internalExecuteContract(resp.contractHash, resp.payUrl, resp.offerUrl);
+ }
});
}
diff --git a/lib/wallet/wallet.ts b/lib/wallet/wallet.ts
index 718e7a312..7cb30c358 100644
--- a/lib/wallet/wallet.ts
+++ b/lib/wallet/wallet.ts
@@ -242,9 +242,16 @@ function getWithdrawDenomList(amountAvailable: AmountJson,
let remaining = Amounts.copy(amountAvailable);
let ds: Denomination[] = [];
+ console.log("available denoms");
+ console.log(denoms);
+
denoms = denoms.filter(isWithdrawableDenom);
denoms.sort((d1, d2) => Amounts.cmp(d2.value, d1.value));
+ console.log("withdrawable denoms");
+ console.log(denoms);
+
+
// This is an arbitrary number of coins
// we can withdraw in one go. It's not clear if this limit
// is useful ...
diff --git a/lib/wallet/wxMessaging.ts b/lib/wallet/wxMessaging.ts
index faff0d220..95dcb929a 100644
--- a/lib/wallet/wxMessaging.ts
+++ b/lib/wallet/wxMessaging.ts
@@ -54,7 +54,7 @@ function makeHandlers(db: IDBDatabase,
return exportDb(db);
},
["ping"]: function(detail, sender) {
- return Promise.resolve({});
+ return Promise.resolve(paymentRequestCache[sender.tab.id]);
},
["reset"]: function(detail, sender) {
if (db) {
@@ -237,8 +237,13 @@ class ChromeNotifier implements Notifier {
}
+/**
+ * Mapping from tab ID to payment information (if any).
+ */
+let paymentRequestCache = {};
+
function handleHttpPayment(headerList: chrome.webRequest.HttpHeader[],
- url): any {
+ url: string, tabId: number): any {
const headers = {};
for (let kv of headerList) {
headers[kv.name.toLowerCase()] = kv.value;
@@ -246,12 +251,8 @@ function handleHttpPayment(headerList: chrome.webRequest.HttpHeader[],
const contractUrl = headers["x-taler-contract-url"];
if (contractUrl !== undefined) {
- // The web shop is proposing a contract, we need to fetch it
- // and show it to the user
- const walletUrl = URI(chrome.extension.getURL(
- "pages/offer-contract-from.html"));
- walletUrl.query({contractUrl});
- return {redirectUrl: walletUrl.href()};
+ paymentRequestCache[tabId] = {type: "fetch", contractUrl};
+ return;
}
const contractHash = headers["x-taler-contract-hash"];
@@ -265,10 +266,13 @@ function handleHttpPayment(headerList: chrome.webRequest.HttpHeader[],
// Offer URL is optional
const offerUrl = headers["x-taler-offer-url"];
- const walletUrl = URI(chrome.extension.getURL(
- "pages/execute-payment.html"));
- walletUrl.query({contractHash, offerUrl, payUrl});
- return {redirectUrl: walletUrl.href()};
+ paymentRequestCache[tabId] = {
+ type: "execute",
+ offerUrl,
+ payUrl,
+ contractHash
+ };
+ return;
}
// looks like it's not a taler request, it might be
@@ -331,7 +335,10 @@ export function wxMain() {
if (details.statusCode != 402) {
return;
}
- return handleHttpPayment(details.responseHeaders, details.url);
+ console.log(`got 402 from ${details.url}`);
+ return handleHttpPayment(details.responseHeaders,
+ details.url,
+ details.tabId);
}, {urls: ["<all_urls>"]}, ["responseHeaders", "blocking"]);
diff --git a/pages/execute-payment.html b/pages/execute-payment.html
deleted file mode 100644
index b2ed86562..000000000
--- a/pages/execute-payment.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
- <title>Taler Wallet: Confirm Reserve Creation</title>
-
- <link rel="stylesheet" type="text/css" href="../style/lang.css">
-
- <script src="../lib/vendor/URI.js"></script>
- <script src="../lib/vendor/mithril.js"></script>
- <script src="../lib/vendor/lodash.core.min.js"></script>
- <script src="../lib/vendor/system-csp-production.src.js"></script>
- <script src="../lib/vendor/jed.js"></script>
- <script src="../i18n/strings.js"></script>
- <script src="../lib/i18n.js"></script>
- <script src="../lib/module-trampoline.js"></script>
-
- <style>
- #main {
- border: solid 1px black;
- border-radius: 10px;
- margin: auto;
- max-width: 50%;
- padding: 2em;
- }
-
- button.accept {
- background-color: #5757D2;
- border: 1px solid black;
- border-radius: 5px;
- margin: 1em 0;
- padding: 0.5em;
- font-weight: bold;
- color: white;
- }
- button.linky {
- background:none!important;
- border:none;
- padding:0!important;
-
- font-family:arial,sans-serif;
- color:#069;
- text-decoration:underline;
- cursor:pointer;
- }
-
- input.url {
- width: 25em;
- }
-
-
- button.accept:disabled {
- background-color: #dedbe8;
- border: 1px solid white;
- border-radius: 5px;
- margin: 1em 0;
- padding: 0.5em;
- font-weight: bold;
- color: #2C2C2C;
- }
-
- .errorbox {
- border: 1px solid;
- display: inline-block;
- margin: 1em;
- padding: 1em;
- font-weight: bold;
- background: #FF8A8A;
- }
- </style>
-</head>
-
-<body>
- <section id="main">
- <h1>GNU Taler Wallet</h1>
- Executing payment ...
- </section>
-</body>
-
-</html>
diff --git a/pages/offer-contract-from.html b/pages/offer-contract-from.html
deleted file mode 100644
index 7bf017c4e..000000000
--- a/pages/offer-contract-from.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
- <title>Taler Wallet: Confirm Reserve Creation</title>
-
- <link rel="stylesheet" type="text/css" href="../style/lang.css">
-
- <script src="../lib/vendor/URI.js"></script>
- <script src="../lib/vendor/mithril.js"></script>
- <script src="../lib/vendor/lodash.core.min.js"></script>
- <script src="../lib/vendor/system-csp-production.src.js"></script>
- <script src="../lib/vendor/jed.js"></script>
- <script src="../i18n/strings.js"></script>
- <script src="../lib/i18n.js"></script>
- <script src="../lib/module-trampoline.js"></script>
-
- <style>
- #main {
- border: solid 1px black;
- border-radius: 10px;
- margin: auto;
- max-width: 50%;
- padding: 2em;
- }
-
- button.accept {
- background-color: #5757D2;
- border: 1px solid black;
- border-radius: 5px;
- margin: 1em 0;
- padding: 0.5em;
- font-weight: bold;
- color: white;
- }
- button.linky {
- background:none!important;
- border:none;
- padding:0!important;
-
- font-family:arial,sans-serif;
- color:#069;
- text-decoration:underline;
- cursor:pointer;
- }
-
- input.url {
- width: 25em;
- }
-
-
- button.accept:disabled {
- background-color: #dedbe8;
- border: 1px solid white;
- border-radius: 5px;
- margin: 1em 0;
- padding: 0.5em;
- font-weight: bold;
- color: #2C2C2C;
- }
-
- .errorbox {
- border: 1px solid;
- display: inline-block;
- margin: 1em;
- padding: 1em;
- font-weight: bold;
- background: #FF8A8A;
- }
- </style>
-</head>
-
-<body>
- <section id="main">
- <h1>GNU Taler Wallet</h1>
- Fetching contract ...
- </section>
-</body>
-
-</html>
diff --git a/pages/offer-contract-from.tsx b/pages/offer-contract-from.tsx
deleted file mode 100644
index 389e96876..000000000
--- a/pages/offer-contract-from.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- This file is part of TALER
- (C) 2015 GNUnet e.V.
-
- 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 3, 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Download a contract from a Url (given as query parameter 'contractUrl' to
- * this page) and offer the contract to the user.
- *
- * @author Florian Dold
- */
-
-
-export function main() {
- const url = URI(document.location.href);
- const query: any = URI.parseQuery(url.query());
-
-
-} \ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 5fa388aa9..44814dec5 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -32,7 +32,6 @@
"pages/show-db.ts",
"pages/confirm-contract.tsx",
"pages/confirm-create-reserve.tsx",
- "pages/offer-contract-from.tsx",
"test/tests/taler.ts"
]
} \ No newline at end of file