aboutsummaryrefslogtreecommitdiff
path: root/content_scripts
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 /content_scripts
parent4b67f220e7d9ab4a7d7a190892f028995baa9902 (diff)
rudimentary 402 handling
Diffstat (limited to 'content_scripts')
-rw-r--r--content_scripts/notify.ts146
1 files changed, 143 insertions, 3 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);
+ }
});
}