From 4bba46b53eb93de669b91c3078cd04ac13a0647c Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sun, 20 Dec 2015 20:05:06 +0100 Subject: payment --- extension/background/emscriptif.js | 20 ++++++-- extension/background/emscriptif.ts | 22 ++++++-- extension/background/wallet.js | 65 +++++++++++++---------- extension/background/wallet.ts | 80 +++++++++++++++++++---------- extension/content_scripts/notify.js | 43 +++++++++++++--- extension/content_scripts/notify.ts | 45 +++++++++++++--- extension/manifest.json | 4 +- extension/pages/confirm-contract.js | 10 ++-- extension/pages/confirm-contract.tsx | 11 ++-- extension/pages/confirm-create-reserve.html | 1 + extension/pages/confirm-create-reserve.js | 75 ++++++++++++--------------- extension/popup/balance-overview.js | 15 ------ extension/popup/balance-overview.tsx | 17 ------ extension/tsconfig.json | 4 +- 14 files changed, 252 insertions(+), 160 deletions(-) diff --git a/extension/background/emscriptif.js b/extension/background/emscriptif.js index e9e118ed3..c12c41416 100644 --- a/extension/background/emscriptif.js +++ b/extension/background/emscriptif.js @@ -268,6 +268,19 @@ class PackedArenaObject extends ArenaObject { emsc.hash(this.nativePtr, this.size(), x.nativePtr); return x; } + hexdump() { + let bytes = []; + for (let i = 0; i < this.size(); i++) { + let b = Module.getValue(this.getNative() + i, "i8"); + b = (b + 256) % 256; + bytes.push("0".concat(b.toString(16)).slice(-2)); + } + let lines = []; + for (let i = 0; i < bytes.length; i += 8) { + lines.push(bytes.slice(i, i + 8).join(",")); + } + return lines.join("\n"); + } } class AmountNbo extends PackedArenaObject { size() { @@ -496,7 +509,7 @@ class AbsoluteTimeNbo extends PackedArenaObject { if (m.length != 2) { throw Error(); } - let n = parseInt(m[1]); + let n = parseInt(m[1]) * 1000000; // XXX: This only works up to 54 bit numbers. set64(x.getNative(), n); return x; @@ -508,14 +521,15 @@ class AbsoluteTimeNbo extends PackedArenaObject { // XXX: This only works up to 54 bit numbers. function set64(p, n) { for (let i = 0; i < 8; ++i) { - Module.setValue(p + (8 - i), n & 0xFF, "i8"); - n >>>= 8; + Module.setValue(p + (7 - i), n & 0xFF, "i8"); + n = Math.floor(n / 256); } } class UInt64 extends PackedArenaObject { static fromNumber(n) { let x = new UInt64(); x.alloc(); + console.log("Creating UINT64 with", n); set64(x.getNative(), n); return x; } diff --git a/extension/background/emscriptif.ts b/extension/background/emscriptif.ts index 80e62cccc..2648b5964 100644 --- a/extension/background/emscriptif.ts +++ b/extension/background/emscriptif.ts @@ -419,6 +419,21 @@ abstract class PackedArenaObject extends ArenaObject { emsc.hash(this.nativePtr, this.size(), x.nativePtr); return x; } + + + hexdump() { + let bytes: string[] = []; + for (let i = 0; i < this.size(); i++) { + let b = Module.getValue(this.getNative() + i, "i8"); + b = (b + 256) % 256; + bytes.push("0".concat(b.toString(16)).slice(-2)); + } + let lines = []; + for (let i = 0; i < bytes.length; i+=8) { + lines.push(bytes.slice(i, i+8).join(",")); + } + return lines.join("\n"); + } } @@ -715,7 +730,7 @@ class AbsoluteTimeNbo extends PackedArenaObject { if (m.length != 2) { throw Error(); } - let n = parseInt(m[1]); + let n = parseInt(m[1]) * 1000000; // XXX: This only works up to 54 bit numbers. set64(x.getNative(), n); return x; @@ -730,8 +745,8 @@ class AbsoluteTimeNbo extends PackedArenaObject { // XXX: This only works up to 54 bit numbers. function set64(p: number, n: number) { for (let i = 0; i < 8; ++i) { - Module.setValue(p + (8 - i), n & 0xFF, "i8"); - n >>>= 8; + Module.setValue(p + (7 - i), n & 0xFF, "i8"); + n = Math.floor(n / 256); } } @@ -741,6 +756,7 @@ class UInt64 extends PackedArenaObject { static fromNumber(n: number): UInt64 { let x = new UInt64(); x.alloc(); + console.log("Creating UINT64 with", n); set64(x.getNative(), n); return x; } diff --git a/extension/background/wallet.js b/extension/background/wallet.js index 8aec5ecb1..a8e62abdf 100644 --- a/extension/background/wallet.js +++ b/extension/background/wallet.js @@ -48,6 +48,7 @@ function signDeposit(db, offer, cds) { let newAmount = new Amount(cd.coin.currentAmount); newAmount.sub(coinSpend); cd.coin.currentAmount = newAmount.toJson(); + console.log("DepositRequestPS: ", d.toPurpose().hexdump()); let coinSig = eddsaSign(d.toPurpose(), EddsaPrivateKey.fromCrock(cd.coin.coinPriv)) .toCrock(); let s = { @@ -145,31 +146,26 @@ function getPossibleMintCoins(db, paymentAmount, depositFeeLimit, allowedMints) } function executePay(db, offer, payCoinInfo, merchantBaseUrl, chosenMint) { return new Promise((resolve, reject) => { - let reqData = {}; - reqData["H_wire"] = offer.contract.H_wire; - reqData["H_contract"] = offer.H_contract; - reqData["transaction_id"] = offer.contract.transaction_id; - reqData["refund_deadline"] = offer.contract.refund_deadline; - reqData["mint"] = URI(chosenMint).hostname(); - reqData["coins"] = payCoinInfo.map((x) => x.sig); - reqData["timestamp"] = offer.contract.timestamp; - let payUrl = URI(offer.contract.pay_url).absoluteTo(merchantBaseUrl); - console.log("Merchant URL", payUrl.href()); - let req = new XMLHttpRequest(); - req.open('post', payUrl.href()); - req.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); - req.send(JSON.stringify(reqData)); - req.addEventListener('readystatechange', (e) => { - if (req.readyState == XMLHttpRequest.DONE) { - if (req.status == 200) { - console.log("Merchant response:", req.responseText); - resolve(); - } - else { - throw Error("bad status " + req.status); - } - } - }); + let payReq = {}; + payReq["H_wire"] = offer.contract.H_wire; + payReq["H_contract"] = offer.H_contract; + payReq["transaction_id"] = offer.contract.transaction_id; + payReq["refund_deadline"] = offer.contract.refund_deadline; + payReq["mint"] = URI(chosenMint).href(); + payReq["coins"] = payCoinInfo.map((x) => x.sig); + payReq["timestamp"] = offer.contract.timestamp; + let payUrl = URI(offer.pay_url).absoluteTo(merchantBaseUrl); + let t = { + contractHash: offer.H_contract, + contract: offer.contract, + payUrl: payUrl.href(), + payReq: payReq + }; + let tx = db.transaction(['transactions'], 'readwrite'); + tx.objectStore('transactions').put(t); + tx.oncomplete = (e) => { + resolve(); + }; }); } function confirmPay(db, detail, sendResponse) { @@ -192,10 +188,25 @@ function confirmPay(db, detail, sendResponse) { return executePay(db, offer, ds, detail.merchantPageUrl, mintUrl); }) .then(() => { - sendResponse({ success: true }); + sendResponse({ + success: true, + }); }); return true; } +function doPayment(db, detail, sendResponse) { + let H_contract = detail.H_contract; + let req = db.transaction(['transactions']).objectStore("transactions").get(H_contract); + console.log("executing contract", H_contract); + req.onsuccess = (e) => { + if (!req.result) { + sendResponse({ success: false, error: "contract not found" }); + return; + } + sendResponse({ success: true, payUrl: req.result.payUrl, payReq: req.result.payReq }); + }; + return true; +} function confirmReserve(db, detail, sendResponse) { let reservePriv = EddsaPrivateKey.create(); let reservePub = reservePriv.getPublicKey(); @@ -592,12 +603,14 @@ function balances(db, detail, sendResponse) { chrome.browserAction.setBadgeText({ text: "" }); openTalerDb().then((db) => { console.log("db loaded"); + updateBadge(db); chrome.runtime.onMessage.addListener(function (req, sender, onresponse) { let dispatch = { "confirm-reserve": confirmReserve, "confirm-pay": confirmPay, "dump-db": dumpDb, "balances": balances, + "execute-payment": doPayment, "reset": reset }; if (req.type in dispatch) { diff --git a/extension/background/wallet.ts b/extension/background/wallet.ts index ee406d2ed..fa26ba1d2 100644 --- a/extension/background/wallet.ts +++ b/extension/background/wallet.ts @@ -38,6 +38,8 @@ interface Offer { contract: Contract; sig: string; H_contract: string; + pay_url: string; + exec_url: string; } interface Contract { @@ -50,7 +52,6 @@ interface Contract { merchant: any; merchant_pub: string; mints: MintInfo[]; - pay_url: string; products: string[]; refund_deadline: string; timestamp: string; @@ -112,6 +113,8 @@ function signDeposit(db: IDBDatabase, newAmount.sub(coinSpend); cd.coin.currentAmount = newAmount.toJson(); + console.log("DepositRequestPS: ", d.toPurpose().hexdump()); + let coinSig = eddsaSign(d.toPurpose(), EddsaPrivateKey.fromCrock(cd.coin.coinPriv)) .toCrock(); @@ -224,37 +227,40 @@ function getPossibleMintCoins(db: IDBDatabase, } +interface Transaction { + contractHash: string; + contract: any; + payUrl: string; + payReq: any; +} + + function executePay(db, offer: Offer, payCoinInfo: PayCoinInfo, merchantBaseUrl: string, chosenMint: string) { return new Promise((resolve, reject) => { - let reqData = {}; - reqData["H_wire"] = offer.contract.H_wire; - reqData["H_contract"] = offer.H_contract; - reqData["transaction_id"] = offer.contract.transaction_id; - reqData["refund_deadline"] = offer.contract.refund_deadline; - reqData["mint"] = URI(chosenMint).hostname(); - reqData["coins"] = payCoinInfo.map((x) => x.sig); - reqData["timestamp"] = offer.contract.timestamp; - let payUrl = URI(offer.contract.pay_url).absoluteTo(merchantBaseUrl); - console.log("Merchant URL", payUrl.href()); - let req = new XMLHttpRequest(); - req.open('post', payUrl.href()); - req.setRequestHeader("Content-Type", - "application/json;charset=UTF-8"); - req.send(JSON.stringify(reqData)); - req.addEventListener('readystatechange', (e) => { - if (req.readyState == XMLHttpRequest.DONE) { - if (req.status == 200) { - console.log("Merchant response:", req.responseText); - resolve(); - } else { - throw Error("bad status " + req.status); - } - } - }); + let payReq = {}; + payReq["H_wire"] = offer.contract.H_wire; + payReq["H_contract"] = offer.H_contract; + payReq["transaction_id"] = offer.contract.transaction_id; + payReq["refund_deadline"] = offer.contract.refund_deadline; + payReq["mint"] = URI(chosenMint).href(); + payReq["coins"] = payCoinInfo.map((x) => x.sig); + payReq["timestamp"] = offer.contract.timestamp; + let payUrl = URI(offer.pay_url).absoluteTo(merchantBaseUrl); + let t: Transaction = { + contractHash: offer.H_contract, + contract: offer.contract, + payUrl: payUrl.href(), + payReq: payReq + }; + let tx = db.transaction(['transactions'], 'readwrite'); + tx.objectStore('transactions').put(t); + tx.oncomplete = (e) => { + resolve(); + }; }); } @@ -283,12 +289,30 @@ function confirmPay(db, detail: ConfirmPayRequest, sendResponse) { return executePay(db, offer, ds, detail.merchantPageUrl, mintUrl); }) .then(() => { - sendResponse({success: true}); + sendResponse({ + success: true, + }); }); return true; } + +function doPayment(db, detail, sendResponse) { + let H_contract = detail.H_contract; + let req = db.transaction(['transactions']).objectStore("transactions").get(H_contract); + console.log("executing contract", H_contract); + req.onsuccess = (e) => { + if (!req.result) { + sendResponse({success: false, error: "contract not found"}); + return; + } + sendResponse({success: true, payUrl: req.result.payUrl, payReq: req.result.payReq}); + }; + return true; +} + + function confirmReserve(db, detail, sendResponse) { let reservePriv = EddsaPrivateKey.create(); let reservePub = reservePriv.getPublicKey(); @@ -732,6 +756,7 @@ chrome.browserAction.setBadgeText({text: ""}); openTalerDb().then((db) => { console.log("db loaded"); + updateBadge(db); chrome.runtime.onMessage.addListener( function(req, sender, onresponse) { let dispatch = { @@ -739,6 +764,7 @@ openTalerDb().then((db) => { "confirm-pay": confirmPay, "dump-db": dumpDb, "balances": balances, + "execute-payment": doPayment, "reset": reset }; if (req.type in dispatch) { diff --git a/extension/content_scripts/notify.js b/extension/content_scripts/notify.js index 4a014e853..899355f8e 100644 --- a/extension/content_scripts/notify.js +++ b/extension/content_scripts/notify.js @@ -1,22 +1,22 @@ // Script that is injected into pages in order to allow merchants pages to // query the availability of Taler. -'use strict'; -document.addEventListener('taler-checkout-probe', function (e) { - let evt = new Event('taler-wallet-present'); +"use strict"; +document.addEventListener("taler-checkout-probe", function (e) { + let evt = new Event("taler-wallet-present"); document.dispatchEvent(evt); console.log("merchant handshake done"); }); -document.addEventListener('taler-wire-probe', function (e) { - let evt = new Event('taler-wallet-present'); +document.addEventListener("taler-wire-probe", function (e) { + let evt = new Event("taler-wallet-present"); document.dispatchEvent(evt); console.log("bank handshake done"); }); -document.addEventListener('taler-checkout-probe', function (e) { - let evt = new Event('taler-wallet-present'); +document.addEventListener("taler-checkout-probe", function (e) { + let evt = new Event("taler-wallet-present"); document.dispatchEvent(evt); console.log("merchant handshake done"); }); -document.addEventListener('taler-create-reserve', function (e) { +document.addEventListener("taler-create-reserve", function (e) { let $ = (x) => document.getElementById(x); console.log("taler-create-reserve with " + JSON.stringify(e.detail)); let form_uri = $(e.detail.form_id).action; @@ -46,3 +46,30 @@ document.addEventListener('taler-contract', function (e) { }; document.location.href = uri.query(params).href(); }); +document.addEventListener('taler-execute-payment', function (e) { + console.log("got taler-execute-payment in content page"); + let msg = { + type: "execute-payment", + detail: { + H_contract: e.detail.H_contract + }, + }; + chrome.runtime.sendMessage(msg, (resp) => { + //console.log("got response from bg page", JSON.stringify(resp)); + if (!resp.success) { + console.log("failure!"); + return; + } + let r = new XMLHttpRequest(); + r.open('post', resp.payUrl); + r.send(JSON.stringify(resp.payReq)); + r.onload = (e) => { + if (r.status != 200) { + console.log("non-200 error"); + console.log(r.responseText); + } + let evt = new Event("taler-payment-result", resp); + document.dispatchEvent(evt); + }; + }); +}); diff --git a/extension/content_scripts/notify.ts b/extension/content_scripts/notify.ts index 7a50582e8..03135dd06 100644 --- a/extension/content_scripts/notify.ts +++ b/extension/content_scripts/notify.ts @@ -1,27 +1,27 @@ // Script that is injected into pages in order to allow merchants pages to // query the availability of Taler. -'use strict'; +"use strict"; -document.addEventListener('taler-checkout-probe', function(e) { - let evt = new Event('taler-wallet-present'); +document.addEventListener("taler-checkout-probe", function(e) { + let evt = new Event("taler-wallet-present"); document.dispatchEvent(evt); console.log("merchant handshake done"); }); -document.addEventListener('taler-wire-probe', function(e) { - let evt = new Event('taler-wallet-present'); +document.addEventListener("taler-wire-probe", function(e) { + let evt = new Event("taler-wallet-present"); document.dispatchEvent(evt); console.log("bank handshake done"); }); -document.addEventListener('taler-checkout-probe', function(e) { - let evt = new Event('taler-wallet-present'); +document.addEventListener("taler-checkout-probe", function(e) { + let evt = new Event("taler-wallet-present"); document.dispatchEvent(evt); console.log("merchant handshake done"); }); -document.addEventListener('taler-create-reserve', function(e: CustomEvent) { +document.addEventListener("taler-create-reserve", function(e: CustomEvent) { let $ = (x) => document.getElementById(x); console.log("taler-create-reserve with " + JSON.stringify(e.detail)); let form_uri = ($(e.detail.form_id)).action; @@ -52,3 +52,32 @@ document.addEventListener('taler-contract', function(e: CustomEvent) { }; document.location.href = uri.query(params).href(); }); + + +document.addEventListener('taler-execute-payment', function(e: CustomEvent) { + console.log("got taler-execute-payment in content page"); + let msg = { + type: "execute-payment", + detail: { + H_contract: e.detail.H_contract + }, + }; + chrome.runtime.sendMessage(msg, (resp) => { + //console.log("got response from bg page", JSON.stringify(resp)); + if (!resp.success) { + console.log("failure!"); + return; + } + let r = new XMLHttpRequest(); + r.open('post', resp.payUrl); + r.send(JSON.stringify(resp.payReq)); + r.onload = (e) => { + if (r.status != 200) { + console.log("non-200 error"); + console.log(r.responseText); + } + let evt = new Event("taler-payment-result", resp); + document.dispatchEvent(evt); + }; + }); +}); \ No newline at end of file diff --git a/extension/manifest.json b/extension/manifest.json index 9394e0833..c61dac6ab 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -1,8 +1,8 @@ { "description": "Privacy preserving and transparent payments", "manifest_version": 2, - "name": "Taler Wallet", - "version": "0.1", + "name": "GNU Taler Wallet", + "version": "0.2", "applications": { "gecko": { diff --git a/extension/pages/confirm-contract.js b/extension/pages/confirm-contract.js index 60de27e90..2c12211f6 100644 --- a/extension/pages/confirm-contract.js +++ b/extension/pages/confirm-contract.js @@ -20,8 +20,7 @@ document.addEventListener("DOMContentLoaded", (e) => { console.dir(offer); let source = $_("contract-template").innerHTML; let template = Handlebars.compile(source); - let html = template(offer.contract); - $_("render-contract").innerHTML = html; + $_("render-contract").innerHTML = template(offer.contract); document.getElementById("confirm-pay").addEventListener("click", (e) => { console.log("Query:", JSON.stringify(query)); let d = { @@ -29,13 +28,16 @@ document.addEventListener("DOMContentLoaded", (e) => { merchantPageUrl: query.merchantPageUrl }; chrome.runtime.sendMessage({ type: 'confirm-pay', detail: d }, (resp) => { - console.log("got response", resp); - if ("error" in resp) { + if (!resp.success) { let source = $_("error-template").innerHTML; let template = Handlebars.compile(source); $_("status").innerHTML = template(resp); return; } + document.location.href = URI(d.offer.exec_url) + .absoluteTo(query.merchantPageUrl) + .addQuery({ H_contract: d.offer.H_contract }) + .href(); }); }); }); diff --git a/extension/pages/confirm-contract.tsx b/extension/pages/confirm-contract.tsx index 040f13ea3..968f5af7a 100644 --- a/extension/pages/confirm-contract.tsx +++ b/extension/pages/confirm-contract.tsx @@ -29,9 +29,7 @@ document.addEventListener("DOMContentLoaded", (e) => { let source = $_("contract-template").innerHTML; let template = Handlebars.compile(source); - let html = template(offer.contract); - - $_("render-contract").innerHTML = html; + $_("render-contract").innerHTML = template(offer.contract); document.getElementById("confirm-pay").addEventListener("click", (e) => { console.log("Query:", JSON.stringify(query)); @@ -40,13 +38,16 @@ document.addEventListener("DOMContentLoaded", (e) => { merchantPageUrl: query.merchantPageUrl }; chrome.runtime.sendMessage({type:'confirm-pay', detail: d}, (resp) => { - console.log("got response", resp); - if ("error" in resp) { + if (!resp.success) { let source = $_("error-template").innerHTML; let template = Handlebars.compile(source); $_("status").innerHTML = template(resp); return; } + document.location.href = URI(d.offer.exec_url) + .absoluteTo(query.merchantPageUrl) + .addQuery({H_contract: d.offer.H_contract}) + .href(); }); }); }); diff --git a/extension/pages/confirm-create-reserve.html b/extension/pages/confirm-create-reserve.html index d89fd0b13..be718da7d 100644 --- a/extension/pages/confirm-create-reserve.html +++ b/extension/pages/confirm-create-reserve.html @@ -4,6 +4,7 @@ Taler Wallet: Confirm Reserve Creation + diff --git a/extension/pages/confirm-create-reserve.js b/extension/pages/confirm-create-reserve.js index 5c35121e3..7c3a5a572 100644 --- a/extension/pages/confirm-create-reserve.js +++ b/extension/pages/confirm-create-reserve.js @@ -1,43 +1,36 @@ "use strict"; - -let url = URI(document.location.href); -let query = URI.parseQuery(url.query()); - -function updateAmount() { - let showAmount = document.getElementById("show-amount"); - console.log("Query is " + JSON.stringify(query)); - let s = query.amount_str; - if (!s) { - document.body.innerHTML = "Oops, something went wrong."; - return; - } - showAmount.textContent = s; -} - -function clone(obj) { - // This is faster than it looks ... - return JSON.parse(JSON.stringify(obj)); -} - -document.addEventListener("DOMContentLoaded", (e) => { - updateAmount(); - - document.getElementById("confirm").addEventListener("click", (e) => { - let d = clone(query); - d.mint = document.getElementById('mint-url').value; - chrome.runtime.sendMessage({type:'confirm-reserve', detail: d}, (resp) => { - if (resp.success === true) { - document.location.href = resp.backlink; - } else { - document.body.innerHTML = - `Oops, something went wrong. - The bank responded with HTTP status code ${resp.status}. - Here is some more info: -
${resp.text}
`; - } +var ConfirmCreateReserve; +(function (ConfirmCreateReserve) { + let url = URI(document.location.href); + let query = URI.parseQuery(url.query()); + function updateAmount() { + let showAmount = document.getElementById("show-amount"); + console.log("Query is " + JSON.stringify(query)); + let s = query.amount_str; + if (!s) { + document.body.innerHTML = "Oops, something went wrong."; + return; + } + showAmount.textContent = s; + } + function clone(obj) { + // This is faster than it looks ... + return JSON.parse(JSON.stringify(obj)); + } + document.addEventListener("DOMContentLoaded", (e) => { + updateAmount(); + document.getElementById("confirm").addEventListener("click", (e) => { + let d = clone(query); + d.mint = document.getElementById('mint-url').value; + chrome.runtime.sendMessage({ type: 'confirm-reserve', detail: d }, (resp) => { + if (resp.success === true) { + document.location.href = resp.backlink; + } + else { + document.body.innerHTML = + React.createElement("div", null, "Oops, something went wrong." + ' ' + "The bank responded with HTTP status code $", resp.status, "." + ' ' + "Here is some more info:", React.createElement("pre", null, resp.text), "`"); + } + }); + }); }); - - }); -}); - - +})(ConfirmCreateReserve || (ConfirmCreateReserve = {})); diff --git a/extension/popup/balance-overview.js b/extension/popup/balance-overview.js index 946ddc6b3..6b6aaf794 100644 --- a/extension/popup/balance-overview.js +++ b/extension/popup/balance-overview.js @@ -1,19 +1,4 @@ "use strict"; -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', (e) => { console.log("content loaded"); chrome.runtime.sendMessage({ type: "balances" }, function (wallet) { diff --git a/extension/popup/balance-overview.tsx b/extension/popup/balance-overview.tsx index bc0e80ee6..a78111bb1 100644 --- a/extension/popup/balance-overview.tsx +++ b/extension/popup/balance-overview.tsx @@ -1,22 +1,5 @@ "use strict"; -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', (e) => { console.log("content loaded"); chrome.runtime.sendMessage({type: "balances"}, function(wallet) { diff --git a/extension/tsconfig.json b/extension/tsconfig.json index da6561ffe..669c264e6 100644 --- a/extension/tsconfig.json +++ b/extension/tsconfig.json @@ -8,8 +8,10 @@ "background/emscriptif.ts", "background/db.ts", "lib/util.ts", + "lib/polyfill-react.ts", "content_scripts/notify.ts", "popup/balance-overview.tsx", - "pages/confirm-contract.tsx" + "pages/confirm-contract.tsx", + "pages/confirm-create-reserve.tsx" ] } -- cgit v1.2.3