diff options
Diffstat (limited to 'talermerchantdemos/blog/static/web-common/taler-wallet-lib.js')
-rw-r--r-- | talermerchantdemos/blog/static/web-common/taler-wallet-lib.js | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/talermerchantdemos/blog/static/web-common/taler-wallet-lib.js b/talermerchantdemos/blog/static/web-common/taler-wallet-lib.js new file mode 100644 index 0000000..2fe1c20 --- /dev/null +++ b/talermerchantdemos/blog/static/web-common/taler-wallet-lib.js @@ -0,0 +1,446 @@ +/* + @source https://www.git.taler.net/?p=web-common.git;a=blob_plain;f=taler-wallet-lib.ts;hb=HEAD + @license magnet:?xt=urn:btih:5de60da917303dbfad4f93fb1b985ced5a89eac2&dn=lgpl-2.1.txt LGPL v21 + + @licstart The following is the entire license notice for the + JavaScript code in this page. + + Copyright (C) 2015, 2016 INRIA + + 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. + + @author Marcello Stanisci + @author Florian Dold +*/ +(function (factory) { + if (typeof module === "object" && typeof module.exports === "object") { + var v = factory(require, exports); + if (v !== undefined) module.exports = v; + } + else if (typeof define === "function" && define.amd) { + define(["require", "exports"], factory); + } +})(function (require, exports) { + "use strict"; + var taler; + (function (taler) { + "use strict"; + var logVerbose = false; + try { + logVerbose = !!localStorage.getItem("taler-log-verbose"); + } + catch (e) { + } + var presentHandlers = []; + var absentHandlers = []; + // Are we running as the content script of an + // extension (and not just from a normal page)? + var runningInExtension = false; + var callSeqId = 1; + var installed = false; + var probeExecuted = false; + var pageLoaded = false; + var errorHandler = undefined; + var sheet; + function onError(handler) { + if (errorHandler) { + console.warn("Overriding error handler"); + } + errorHandler = handler; + } + taler.onError = onError; + /** + * Error handler for things that go wrong in the merchant + * frontend browser code. + */ + function raise_error(reason, detail) { + if (errorHandler) { + errorHandler(reason, detail); + return; + } + alert("Failure: " + reason + ". No error handler installed. Open the developer console for more information."); + console.error(reason, detail); + console.warn("No custom error handler set."); + } + function callWallet(funcName, args, onResult) { + var detail = JSON.parse(JSON.stringify(args || {})); + var callId = callSeqId++; + detail.callId = callId; + var onTimeout = function () { + console.warn("timeout for invocation of " + funcName); + }; + var timeoutHandle = setTimeout(onTimeout, 1000); + var handler = function (evt) { + if (evt.detail.callId !== callId) { + return; + } + if (onResult) { + onResult(evt.detail); + } + clearTimeout(timeoutHandle); + document.removeEventListener(funcName + "-result", handler); + }; + document.addEventListener(funcName + "-result", handler); + var evt = new CustomEvent(funcName, { detail: detail }); + document.dispatchEvent(evt); + } + /** + * Confirm that a reserve was created. + * + * Used by tightly integrated bank portals. + */ + function confirmReserve(reservePub) { + if (!installed) { + logVerbose && console.log("delaying confirmReserve"); + taler.onPresent(function () { + confirmReserve(reservePub); + }); + return; + } + callWallet("taler-confirm-reserve", { reserve_pub: reservePub }); + } + taler.confirmReserve = confirmReserve; + function createReserve(callbackUrl, amount, wtTypes, suggestedExchangeUrl) { + if (!installed) { + logVerbose && console.log("delaying createReserve"); + taler.onPresent(function () { + createReserve(callbackUrl, amount, wtTypes, suggestedExchangeUrl); + }); + return; + } + var args = { + callback_url: callbackUrl, + amount: amount, + wt_types: wtTypes, + suggested_exchange_url: suggestedExchangeUrl + }; + callWallet("taler-create-reserve", args); + } + taler.createReserve = createReserve; + function handlePaymentResponse(walletResp) { + /** + * 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(r) { + var timeoutHandle = null; + function err() { + raise_error("pay-failed", { status: r.status, response: r.responseText }); + } + function onResp() { + if (timeoutHandle != null) { + clearTimeout(timeoutHandle); + timeoutHandle = null; + } + err(); + } + function onTimeout() { + timeoutHandle = null; + err(); + } + callWallet("taler-payment-failed", { H_contract: walletResp.H_contract }, onResp); + timeoutHandle = setTimeout(onTimeout, 200); + } + logVerbose && console.log("handling taler-notify-payment: ", walletResp); + // Payment timeout in ms. + var timeout_ms = 1000; + // Current request. + var r; + var timeoutHandle = null; + function sendPay() { + r = new XMLHttpRequest(); + r.open("post", walletResp.contract.pay_url); + r.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + r.send(JSON.stringify(walletResp.payReq)); + r.onload = function () { + if (!r) { + return; + } + switch (r.status) { + case 200: + var merchantResp = JSON.parse(r.responseText); + logVerbose && console.log("got success from pay_url"); + callWallet("taler-payment-succeeded", { H_contract: walletResp.H_contract, merchantSig: merchantResp.sig }, function () { + var nextUrl = walletResp.contract.fulfillment_url; + logVerbose && console.log("taler-payment-succeeded done, going to", nextUrl); + window.location.href = nextUrl; + window.location.reload(true); + }); + break; + default: + handleFailedPayment(r); + 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); + logVerbose && console.log("sendPay timed out, retrying in ", timeout_ms, "ms"); + sendPay(); + } + timeoutHandle = setTimeout(retry, timeout_ms); + } + sendPay(); + } + function onPresent(f) { + presentHandlers.push(f); + } + taler.onPresent = onPresent; + function onAbsent(f) { + absentHandlers.push(f); + } + taler.onAbsent = onAbsent; + function internalPay(p) { + // either the callback gets called, + // or the wallet will redirect the browser + callWallet("taler-pay", p, handlePaymentResponse); + } + taler.internalPay = internalPay; + function pay(p) { + if (!installed) { + logVerbose && console.log("delaying call to 'pay' until GNU Taler wallet is present"); + taler.onPresent(function () { + pay(p); + }); + return; + } + internalPay(p); + } + taler.pay = pay; + function internalAddAuditor(d) { + // either the callback gets called, + // or the wallet will redirect the browser + callWallet("taler-add-auditor", d); + } + taler.internalAddAuditor = internalAddAuditor; + function addAuditor(d) { + if (!installed) { + logVerbose && console.log("delaying call to 'addAuditor' until GNU Taler wallet is present"); + taler.onPresent(function () { + addAuditor(d); + }); + return; + } + internalAddAuditor(d); + } + taler.addAuditor = addAuditor; + function internalCheckAuditor(url) { + return new Promise(function (resolve, reject) { + callWallet("taler-check-auditor", url, function (x) { return resolve(x); }); + }); + } + taler.internalCheckAuditor = internalCheckAuditor; + /** + * Check if an auditor is already added to the wallet. + * + * Same-origin restrictions apply. + */ + function checkAuditor(url) { + if (!installed) { + logVerbose && console.log("delaying call to 'checkAuditor' until GNU Taler wallet is present"); + return new Promise(function (resolve, reject) { + taler.onPresent(function () { + resolve(checkAuditor(url)); + }); + }); + } + return internalCheckAuditor(url); + } + taler.checkAuditor = checkAuditor; + function initTaler() { + function handleUninstall() { + installed = false; + // not really true, but we want "uninstalled" to be shown + firstTimeoutCalled = true; + announce(); + } + function handleProbe() { + probeExecuted = true; + if (!installed) { + logVerbose && console.log("taler install detected"); + installed = true; + announce(); + } + } + function probeTaler() { + probeExecuted = false; + var eve = new Event("taler-probe"); + document.dispatchEvent(eve); + } + var firstTimeoutCalled = false; + function onProbeTimeout() { + if (!probeExecuted) { + if (installed || !firstTimeoutCalled) { + installed = false; + firstTimeoutCalled = true; + logVerbose && console.log("taler uninstall detected"); + announce(); + } + } + // try again, maybe it'll be installed ... + probeTaler(); + } + /** + * Announce presence/absence and update stylesheets. + * + * Only called after document.readyState is at least "interactive". + */ + function announce() { + if (!pageLoaded) { + logVerbose && console.log("page not loaded yet, announcing later"); + return; + } + setStyles(); + if (installed) { + logVerbose && console.log("announcing installed"); + for (var i = 0; i < presentHandlers.length; i++) { + presentHandlers[i](); + } + } + else { + if (firstTimeoutCalled) { + logVerbose && console.log("announcing uninstalled"); + for (var i = 0; i < absentHandlers.length; i++) { + absentHandlers[i](); + } + } + else { + logVerbose && console.log("announcing nothing"); + } + } + } + function setStyles() { + if (!sheet || !sheet.cssRules) { + return; + } + while (sheet.cssRules.length > 0) { + sheet.deleteRule(0); + } + if (installed) { + sheet.insertRule(".taler-installed-hide { display: none; }", 0); + sheet.insertRule(".taler-probed-hide { display: none; }", 0); + } + else { + sheet.insertRule(".taler-installed-show { display: none; }", 0); + if (firstTimeoutCalled) { + sheet.insertRule(".taler-probed-hide { display: none; }", 0); + } + else { + // We're still doing the detection + sheet.insertRule(".taler-installed-hide { display: none; }", 0); + } + } + } + function initStyle() { + logVerbose && console.log("taking over styles"); + var name = "taler-presence-stylesheet"; + var content = "/* Taler stylesheet controlled by JS */"; + var style = document.getElementById(name); + if (!style) { + style = document.createElement("style"); + // Needed by WebKit + style.appendChild(document.createTextNode(content)); + style.id = name; + document.head.appendChild(style); + sheet = style.sheet; + } + else { + // We've taken over the stylesheet now, + // make it clear by clearing all the rules in it + // and making it obvious in the DOM. + if (style.tagName.toLowerCase() === "style") { + style.innerText = content; + } + if (!style.sheet) { + throw Error("taler-presence-stylesheet should be a style sheet (<link> or <style>)"); + } + sheet = style.sheet; + while (sheet.cssRules.length > 0) { + sheet.deleteRule(0); + } + } + } + function onPageLoad() { + pageLoaded = true; + if (document.readyState == "complete") { + initStyle(); + } + else { + var listener = function () { + initStyle(); + setStyles(); + }; + window.addEventListener("load", listener); + } + // We only start the timeout after the page is interactive. + window.setInterval(onProbeTimeout, 300); + announce(); + } + probeTaler(); + document.addEventListener("taler-probe-result", handleProbe, false); + document.addEventListener("taler-uninstall", handleUninstall, false); + // Handle the case where the JavaScript is loaded after the page + // has been loaded for the first time. + if (document.readyState == "loading") { + document.addEventListener("DOMContentLoaded", onPageLoad, false); + } + else { + onPageLoad(); + } + } + function onPageLoadInExtension() { + if (document.documentElement.getAttribute("data-taler-nojs")) { + logVerbose && console.log("doing taler initialization from extension (nojs)"); + initTaler(); + } + } + var caught = false; + try { + chrome.runtime.sendMessage({ type: "ping" }); + } + catch (e) { + caught = true; + } + if (caught) { + logVerbose && console.log("running taler-wallet-lib from page"); + initTaler(); + } + else { + logVerbose && console.log("running taler-wallet-lib from extension"); + runningInExtension = true; + // Wait for even style sheets to load + if (document.readyState != "complete") { + window.addEventListener("load", function () { return onPageLoadInExtension(); }); + } + else { + onPageLoadInExtension(); + } + } + })(taler = exports.taler || (exports.taler = {})); +}); +// @license-end |