diff options
author | Florian Dold <florian.dold@gmail.com> | 2016-09-08 17:26:31 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2016-09-08 17:26:31 +0200 |
commit | a164ea91838b0dd2506acbd67e1b3720abaa7e01 (patch) | |
tree | 93b698668cffcc93c2ba3294ff8845dd4d42e439 | |
parent | 4b67f220e7d9ab4a7d7a190892f028995baa9902 (diff) |
rudimentary 402 handling
-rw-r--r-- | content_scripts/notify.ts | 146 | ||||
-rw-r--r-- | lib/wallet/wallet.ts | 7 | ||||
-rw-r--r-- | lib/wallet/wxMessaging.ts | 33 | ||||
-rw-r--r-- | pages/execute-payment.html | 80 | ||||
-rw-r--r-- | pages/offer-contract-from.html | 80 | ||||
-rw-r--r-- | pages/offer-contract-from.tsx | 30 | ||||
-rw-r--r-- | tsconfig.json | 1 |
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 |