This commit is contained in:
Florian Dold 2016-01-26 17:21:17 +01:00
parent 5f996fedbc
commit d2f1cb3234
21 changed files with 486 additions and 5667 deletions

View File

@ -3,5 +3,6 @@ node_modules/
background/*.js background/*.js
lib/wallet/*.js lib/wallet/*.js
lib/*.js lib/*.js
!lib/module-trampoline.js
popup/*.js popup/*.js
test/tests/*.js test/tests/*.js

View File

@ -18,6 +18,11 @@
/// <reference path="../lib/decl/chrome/chrome.d.ts" /> /// <reference path="../lib/decl/chrome/chrome.d.ts" />
"use strict"; "use strict";
console.log("Taler injected"); console.log("Taler injected");
function subst(url, H_contract) {
url = url.replace("${H_contract}", H_contract);
url = url.replace("${$}", "$");
return url;
}
document.addEventListener("taler-probe", function (e) { document.addEventListener("taler-probe", function (e) {
var evt = new Event("taler-wallet-present"); var evt = new Event("taler-wallet-present");
document.dispatchEvent(evt); document.dispatchEvent(evt);
@ -55,10 +60,15 @@ document.addEventListener("taler-contract", function (e) {
}); });
document.addEventListener('taler-execute-payment', function (e) { document.addEventListener('taler-execute-payment', function (e) {
console.log("got taler-execute-payment in content page"); console.log("got taler-execute-payment in content page");
if (!e.detail.pay_url) {
console.log("field 'pay_url' missing in taler-execute-payment event");
return;
}
var payUrl = e.detail.pay_url;
var msg = { var msg = {
type: "execute-payment", type: "execute-payment",
detail: { detail: {
H_contract: e.detail.H_contract H_contract: e.detail.H_contract,
}, },
}; };
chrome.runtime.sendMessage(msg, function (resp) { chrome.runtime.sendMessage(msg, function (resp) {
@ -66,38 +76,29 @@ document.addEventListener('taler-execute-payment', function (e) {
console.log("failure!"); console.log("failure!");
return; return;
} }
console.log("Making request to ", resp.payUrl); var contract = resp.contract;
if (!contract) {
throw Error("contract missing");
}
var payReq = Object.assign({}, resp.payReq);
if (e.detail.require_contract) {
payReq.contract = contract;
}
console.log("Making request to ", payUrl);
var r = new XMLHttpRequest(); var r = new XMLHttpRequest();
r.open('post', resp.payUrl); r.open('post', payUrl);
r.send(JSON.stringify(resp.payReq)); r.send(JSON.stringify(payReq));
var detail = {}; r.onload = function () {
r.onload = function (e) {
switch (r.status) { switch (r.status) {
case 200: case 200:
detail.success = true; console.log("going to", contract.fulfillment_url);
var respJson = JSON.parse(r.responseText); window.location.href = subst(contract.fulfillment_url, e.detail.H_contract);
console.log("respJson:", JSON.stringify(respJson)); window.location.reload(true);
if (!respJson) {
console.log("Invalid JSON in response from $pay_url");
detail.success = false;
break;
}
if (!respJson.fulfillment_url) {
console.log("Missing 'fulfillment_url' in response from $pay_url");
detail.success = false;
break;
}
detail.fulfillmentUrl = respJson.fulfillment_url;
break; break;
default: default:
console.log("Unexpected status code for $pay_url:", r.status); console.log("Unexpected status code for $pay_url:", r.status);
detail.success = false;
break; break;
} }
detail.status = r.status;
detail.responseText = r.responseText;
detail.fulfillmentUrl =
document.dispatchEvent(new CustomEvent("taler-payment-result", { detail: detail }));
}; };
}); });
}); });

View File

@ -23,6 +23,13 @@
console.log("Taler injected"); console.log("Taler injected");
function subst(url: string, H_contract) {
url = url.replace("${H_contract}", H_contract);
url = url.replace("${$}", "$");
return url;
}
document.addEventListener("taler-probe", function(e) { document.addEventListener("taler-probe", function(e) {
let evt = new Event("taler-wallet-present"); let evt = new Event("taler-wallet-present");
document.dispatchEvent(evt); document.dispatchEvent(evt);
@ -65,10 +72,15 @@ document.addEventListener("taler-contract", function(e: CustomEvent) {
document.addEventListener('taler-execute-payment', function(e: CustomEvent) { document.addEventListener('taler-execute-payment', function(e: CustomEvent) {
console.log("got taler-execute-payment in content page"); console.log("got taler-execute-payment in content page");
if (!e.detail.pay_url) {
console.log("field 'pay_url' missing in taler-execute-payment event");
return;
}
let payUrl = e.detail.pay_url;
let msg = { let msg = {
type: "execute-payment", type: "execute-payment",
detail: { detail: {
H_contract: e.detail.H_contract H_contract: e.detail.H_contract,
}, },
}; };
chrome.runtime.sendMessage(msg, (resp) => { chrome.runtime.sendMessage(msg, (resp) => {
@ -76,38 +88,32 @@ document.addEventListener('taler-execute-payment', function(e: CustomEvent) {
console.log("failure!"); console.log("failure!");
return; return;
} }
console.log("Making request to ", resp.payUrl); let contract = resp.contract;
if (!contract) {
throw Error("contract missing");
}
let payReq = Object.assign({}, resp.payReq);
if (e.detail.require_contract) {
payReq.contract = contract;
}
console.log("Making request to ", payUrl);
let r = new XMLHttpRequest(); let r = new XMLHttpRequest();
r.open('post', resp.payUrl); r.open('post', payUrl);
r.send(JSON.stringify(resp.payReq)); r.send(JSON.stringify(payReq));
let detail: any = {}; r.onload = () => {
r.onload = (e) => {
switch (r.status) { switch (r.status) {
case 200: case 200:
detail.success = true; console.log("going to", contract.fulfillment_url);
let respJson = JSON.parse(r.responseText); window.location.href = subst(contract.fulfillment_url,
console.log("respJson:", JSON.stringify(respJson)); e.detail.H_contract);
if (!respJson) { window.location.reload(true);
console.log("Invalid JSON in response from $pay_url");
detail.success = false;
break;
}
if (!respJson.fulfillment_url) {
console.log("Missing 'fulfillment_url' in response from $pay_url");
detail.success = false;
break;
}
detail.fulfillmentUrl = respJson.fulfillment_url;
break; break;
default: default:
console.log("Unexpected status code for $pay_url:", r.status); console.log("Unexpected status code for $pay_url:", r.status);
detail.success = false;
break; break;
} }
detail.status = r.status;
detail.responseText = r.responseText;
detail.fulfillmentUrl =
document.dispatchEvent(new CustomEvent("taler-payment-result", {detail: detail}));
}; };
}); });
}); });

View File

@ -0,0 +1,68 @@
/*
This file is part of TALER
(C) 2016 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, If not, see <http://www.gnu.org/licenses/>
*/
/**
* Boilerplate to initialize the module system and call main()
*/
"use strict";
if (typeof System === "undefined") {
throw Error("system loader not present (must be included before the" +
" trampoline");
}
System.config({
defaultJSExtensions: true,
});
let me = window.location.protocol
+ "//" + window.location.host
+ window.location.pathname.replace(/[.]html$/, ".js");
let domLoaded = false;
document.addEventListener("DOMContentLoaded", function(event) {
domLoaded = true;
});
function execMain(m) {
if (m.main) {
console.log("executing module main");
m.main();
} else {
console.warn("module does not export a main() function");
}
}
console.log("loading", me);
System.import(me)
.then((m) => {
console.log("module imported", me);
if (domLoaded) {
execMain(m);
return;
}
document.addEventListener("DOMContentLoaded", function(event) {
execMain(m);
});
})
.catch((e) => {
console.log("trampoline failed");
console.error(e.stack);
});

File diff suppressed because one or more lines are too long

View File

@ -1404,5 +1404,3 @@ var m = (function app(window, undefined) {
return m; return m;
})(typeof window !== "undefined" ? window : {}); })(typeof window !== "undefined" ? window : {});
if (typeof module === "object" && module != null && module.exports) module.exports = m;
else if (typeof define === "function" && define.amd) define(function() { return m });

View File

@ -89,7 +89,6 @@ class CoinPaySig {
interface ConfirmPayRequest { interface ConfirmPayRequest {
merchantPageUrl: string;
offer: Offer; offer: Offer;
} }
@ -107,8 +106,6 @@ interface Offer {
contract: Contract; contract: Contract;
sig: string; sig: string;
H_contract: string; H_contract: string;
pay_url: string;
exec_url: string;
} }
interface Contract { interface Contract {
@ -140,7 +137,6 @@ interface CoinPaySig_interface {
interface Transaction { interface Transaction {
contractHash: string; contractHash: string;
contract: any; contract: any;
payUrl: string;
payReq: any; payReq: any;
} }
@ -153,8 +149,8 @@ interface Reserve {
interface PaymentResponse { interface PaymentResponse {
payUrl: string;
payReq: any; payReq: any;
contract: Contract;
} }
@ -370,7 +366,6 @@ export class Wallet {
executePay(offer: Offer, executePay(offer: Offer,
payCoinInfo: PayCoinInfo, payCoinInfo: PayCoinInfo,
merchantBaseUrl: string,
chosenMint: string): Promise<void> { chosenMint: string): Promise<void> {
let payReq = {}; let payReq = {};
payReq["H_wire"] = offer.contract.H_wire; payReq["H_wire"] = offer.contract.H_wire;
@ -380,15 +375,12 @@ export class Wallet {
payReq["mint"] = URI(chosenMint).href(); payReq["mint"] = URI(chosenMint).href();
payReq["coins"] = payCoinInfo.map((x) => x.sig); payReq["coins"] = payCoinInfo.map((x) => x.sig);
payReq["timestamp"] = offer.contract.timestamp; payReq["timestamp"] = offer.contract.timestamp;
let payUrl = URI(offer.pay_url).absoluteTo(merchantBaseUrl);
let t: Transaction = { let t: Transaction = {
contractHash: offer.H_contract, contractHash: offer.H_contract,
contract: offer.contract, contract: offer.contract,
payUrl: payUrl.href(), payReq: payReq,
payReq: payReq
}; };
let historyEntry = { let historyEntry = {
type: "pay", type: "pay",
timestamp: (new Date).getTime(), timestamp: (new Date).getTime(),
@ -406,7 +398,7 @@ export class Wallet {
.finish(); .finish();
} }
confirmPay(offer: Offer, merchantPageUrl: string): Promise<any> { confirmPay(offer: Offer): Promise<any> {
return Promise.resolve().then(() => { return Promise.resolve().then(() => {
return this.getPossibleMintCoins(offer.contract.amount, return this.getPossibleMintCoins(offer.contract.amount,
offer.contract.max_fee, offer.contract.max_fee,
@ -417,7 +409,7 @@ export class Wallet {
} }
let mintUrl = Object.keys(mcs)[0]; let mintUrl = Object.keys(mcs)[0];
let ds = Wallet.signDeposit(offer, mcs[mintUrl]); let ds = Wallet.signDeposit(offer, mcs[mintUrl]);
return this.executePay(offer, ds, merchantPageUrl, mintUrl); return this.executePay(offer, ds, mintUrl);
}); });
} }
@ -430,15 +422,14 @@ export class Wallet {
throw Error("contract not found"); throw Error("contract not found");
} }
let resp: PaymentResponse = { let resp: PaymentResponse = {
payUrl: t.payUrl, payReq: t.payReq,
payReq: t.payReq contract: t.contract,
}; };
return resp; return resp;
}); });
}); });
} }
initReserve(reserveRecord) { initReserve(reserveRecord) {
this.updateMintFromUrl(reserveRecord.mint_base_url) this.updateMintFromUrl(reserveRecord.mint_base_url)
.then((mint) => .then((mint) =>
@ -478,55 +469,55 @@ export class Wallet {
} }
return this.http.postForm(req.post_url, form) return this.http.postForm(req.post_url, form)
.then((hresp) => { .then((hresp) => {
// TODO: look at response status code and handle errors appropriately // TODO: look at response status code and handle errors appropriately
let json = JSON.parse(hresp.responseText); let json = JSON.parse(hresp.responseText);
if (!json) { if (!json) {
return { return {
success: false success: false
}; };
} }
let resp: ConfirmReserveResponse = { let resp: ConfirmReserveResponse = {
success: undefined, success: undefined,
backlink: json.redirect_url, backlink: json.redirect_url,
}; };
let reserveRecord = { let reserveRecord = {
reserve_pub: reservePub.toCrock(), reserve_pub: reservePub.toCrock(),
reserve_priv: reservePriv.toCrock(), reserve_priv: reservePriv.toCrock(),
mint_base_url: mintBaseUrl, mint_base_url: mintBaseUrl,
created: now, created: now,
last_query: null, last_query: null,
current_amount: null, current_amount: null,
// XXX: set to actual amount // XXX: set to actual amount
requested_amount: null requested_amount: null
}; };
if (hresp.status != 200) { if (hresp.status != 200) {
resp.success = false; resp.success = false;
return resp; return resp;
} }
let historyEntry = { let historyEntry = {
type: "create-reserve", type: "create-reserve",
timestamp: now, timestamp: now,
detail: { detail: {
requestedAmount, requestedAmount,
reservePub: reserveRecord.reserve_pub, reservePub: reserveRecord.reserve_pub,
} }
}; };
resp.success = true; resp.success = true;
return Query(this.db) return Query(this.db)
.put("reserves", reserveRecord) .put("reserves", reserveRecord)
.put("history", historyEntry) .put("history", historyEntry)
.finish() .finish()
.then(() => { .then(() => {
// Do this in the background // Do this in the background
this.initReserve(reserveRecord); this.initReserve(reserveRecord);
return resp; return resp;
}); });
}); });
} }
@ -652,6 +643,7 @@ export class Wallet {
}); });
} }
withdraw(denom, reserve): Promise<void> { withdraw(denom, reserve): Promise<void> {
return this.withdrawPrepare(denom, reserve) return this.withdrawPrepare(denom, reserve)
.then((pc) => this.withdrawExecute(pc)) .then((pc) => this.withdrawExecute(pc))
@ -741,6 +733,7 @@ export class Wallet {
}); });
} }
/** /**
* Update or add mint DB entry by fetching the /keys information. * Update or add mint DB entry by fetching the /keys information.
* Optionally link the reserve entry to the new or existing * Optionally link the reserve entry to the new or existing
@ -782,11 +775,13 @@ export class Wallet {
.reduce(collectBalances, {}); .reduce(collectBalances, {});
} }
getHistory() { getHistory() {
function collect(x, acc) { function collect(x, acc) {
acc.push(x); acc.push(x);
return acc; return acc;
} }
return Query(this.db) return Query(this.db)
.iter("history", {indexName: "timestamp"}) .iter("history", {indexName: "timestamp"})
.reduce(collect, []) .reduce(collect, [])

View File

@ -81,8 +81,8 @@ System.register(["./wallet", "./db", "./http"], function(exports_1) {
.then(function (r) { .then(function (r) {
sendResponse({ sendResponse({
success: true, success: true,
payUrl: r.payUrl, payReq: r.payReq,
payReq: r.payReq contract: r.contract,
}); });
}) })
.catch(function (e) { .catch(function (e) {
@ -105,6 +105,9 @@ System.register(["./wallet", "./db", "./http"], function(exports_1) {
}); });
return true; return true;
}, },
_a["error-fatal"] = function (db, detail, sendResponse) {
console.log("fatal error from page", detail.url);
},
_a _a
); );
var _a; var _a;

View File

@ -98,8 +98,8 @@ function makeHandlers(wallet) {
.then((r) => { .then((r) => {
sendResponse({ sendResponse({
success: true, success: true,
payUrl: r.payUrl, payReq: r.payReq,
payReq: r.payReq contract: r.contract,
}); });
}) })
.catch((e) => { .catch((e) => {
@ -113,14 +113,17 @@ function makeHandlers(wallet) {
["get-history"]: function(db, detail, sendResponse) { ["get-history"]: function(db, detail, sendResponse) {
// TODO: limit history length // TODO: limit history length
wallet.getHistory() wallet.getHistory()
.then((h) => { .then((h) => {
sendResponse(h); sendResponse(h);
}) })
.catch((e) => { .catch((e) => {
console.error("exception during 'get-history'"); console.error("exception during 'get-history'");
console.error(e.stack); console.error(e.stack);
}); });
return true; return true;
},
["error-fatal"]: function(db, detail, sendResponse) {
console.log("fatal error from page", detail.url);
} }
}; };
} }

View File

@ -0,0 +1,21 @@
/*
This file is part of TALER
(C) 2016 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, If not, see <http://www.gnu.org/licenses/>
*/
export function substituteFulfillmentUrl(url: string, offer) {
url = url.replace("${H_contract}", offer.H_contract);
url = url.replace("${$}", "$");
return url;
}

View File

@ -26,8 +26,8 @@
{ {
"matches": ["*://*/*"], "matches": ["*://*/*"],
"js": [ "js": [
"lib/vendor/system.src.js",
"lib/vendor/URI.js", "lib/vendor/URI.js",
"lib/vendor/system-csp-production.src.js",
"content_scripts/notify.js" "content_scripts/notify.js"
], ],
"run_at": "document_start" "run_at": "document_start"
@ -44,12 +44,10 @@
"lib/vendor/URI.js", "lib/vendor/URI.js",
"lib/vendor/handlebars-v4.0.5.js", "lib/vendor/handlebars-v4.0.5.js",
"lib/emscripten/libwrapper.js", "lib/emscripten/libwrapper.js",
"lib/vendor/system.src.js", "lib/vendor/system-csp-production.src.js",
"background/main.js" "background/main.js"
] ]
}, },
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"minimum_chrome_version": "47.0.2526" "minimum_chrome_version": "47.0.2526"
} }

View File

@ -4,17 +4,14 @@
<head> <head>
<title>Taler Wallet: Confirm Reserve Creation</title> <title>Taler Wallet: Confirm Reserve Creation</title>
<script src="../lib/vendor/URI.js"></script> <script src="../lib/vendor/URI.js"></script>
<script src="../lib/vendor/handlebars-v4.0.5.js"></script> <script src="../lib/vendor/mithril.js"></script>
<script src="../lib/commonHelpers.js"></script> <script src="../lib/i18n.js"></script>
<script src="confirm-contract.js"></script> <script src="../lib/vendor/lodash.core.min.js"></script>
<script src="../lib/vendor/system-csp-production.src.js"></script>
<script src="../lib/module-trampoline.js"></script>
<link rel="stylesheet" type="text/css" href="../style/wallet.css"> <link rel="stylesheet" type="text/css" href="../style/wallet.css">
<script id="contract-template" type="text/x-handlebars-template"> <script id="contract-template" type="text/x-handlebars-template">
Hello, this is the wallet. The merchant "{{merchant.name}}"
wants to enter a contract over {{prettyAmount amount}}
with you.
<p />
Your contract includes these products: Your contract includes these products:
<ul> <ul>
@ -41,15 +38,7 @@
</aside> </aside>
<section id="main"> <section id="main">
<article id="contract"></article>
<article id="contract">
<div id="render-contract"></div>
<button id="confirm-pay">Confirm Payment</button>
<div id="confirm-warning"></div>
</article>
<article id="status"></article>
</section> </section>
</body> </body>

View File

@ -13,47 +13,55 @@
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/ */
/// <reference path="../lib/decl/handlebars/handlebars.d.ts" /> System.register(["../lib/web-common"], function(exports_1) {
"use strict"; /// <reference path="../lib/decl/handlebars/handlebars.d.ts" />
var url = URI(document.location.href); "use strict";
var query = URI.parseQuery(url.query()); var web_common_1;
var $_ = function (x) { return document.getElementById(x); }; function prettyAmount(amount) {
function renderContract(contract) { var v = amount.value + amount.fraction / 1e6;
var showAmount = document.getElementById("show-amount"); return v.toFixed(2) + " " + amount.currency;
$_('merchant-name').innerText = contract.merchant.name; }
} function main() {
function clone(obj) { var url = URI(document.location.href);
// This is faster than it looks ... var query = URI.parseQuery(url.query());
return JSON.parse(JSON.stringify(obj)); var offer = JSON.parse(query.offer);
} console.dir(offer);
Handlebars.registerHelper('prettyAmount', function (amount) { var contract = offer.contract;
var v = amount.value + amount.fraction / 10e6; var Contract = {
return v.toFixed(2) + " " + amount.currency; view: function (ctrl) {
}); return [
document.addEventListener("DOMContentLoaded", function (e) { m("p", (_a = ["Hello, this is the wallet. The merchant \"", "\"\n wants to enter a contract over ", "\n with you."], _a.raw = ["Hello, this is the wallet. The merchant \"", "\"\n wants to enter a contract over ", "\n with you."], i18n(_a, contract.merchant.name, prettyAmount(contract.amount)))),
var offer = JSON.parse(query.offer); m("p", (_b = ["The contract contains the following products:"], _b.raw = ["The contract contains the following products:"], i18n(_b))),
console.dir(offer); m('ul', _.map(contract.products, function (p) { return m("li", p.description + ": " + prettyAmount(p.price)); })),
var source = $_("contract-template").innerHTML; m("button", { onclick: doPayment }, (_c = ["Confirm Payment"], _c.raw = ["Confirm Payment"], i18n(_c)))
var template = Handlebars.compile(source); ];
$_("render-contract").innerHTML = template(offer.contract); var _a, _b, _c;
document.getElementById("confirm-pay").addEventListener("click", function (e) {
console.log("Query:", JSON.stringify(query));
var d = {
offer: JSON.parse(query.offer),
merchantPageUrl: query.merchantPageUrl
};
chrome.runtime.sendMessage({ type: 'confirm-pay', detail: d }, function (resp) {
if (!resp.success) {
var source_1 = $_("error-template").innerHTML;
var template_1 = Handlebars.compile(source_1);
$_("status").innerHTML = template_1(resp);
return;
} }
document.location.href = URI(d.offer.exec_url) };
.absoluteTo(query.merchantPageUrl) m.mount(document.getElementById("contract"), Contract);
.addQuery({ H_contract: d.offer.H_contract }) function doPayment() {
.href(); var d = {
}); offer: offer
}); };
chrome.runtime.sendMessage({ type: 'confirm-pay', detail: d }, function (resp) {
if (!resp.success) {
console.log("confirm-pay error", JSON.stringify(resp));
return;
}
var c = d.offer.contract;
console.log("contract", c);
document.location.href = web_common_1.substituteFulfillmentUrl(c.fulfillment_url, offer);
});
}
}
exports_1("main", main);
return {
setters:[
function (web_common_1_1) {
web_common_1 = web_common_1_1;
}],
execute: function() {
}
}
}); });
//# sourceMappingURL=confirm-contract.js.map //# sourceMappingURL=confirm-contract.js.map

View File

@ -17,55 +17,56 @@
/// <reference path="../lib/decl/handlebars/handlebars.d.ts" /> /// <reference path="../lib/decl/handlebars/handlebars.d.ts" />
"use strict"; "use strict";
let url = URI(document.location.href); import {substituteFulfillmentUrl} from "../lib/web-common";
let query: any = URI.parseQuery(url.query());
let $_ = (x) => document.getElementById(x); declare var m: any;
function renderContract(contract) { function prettyAmount(amount) {
let showAmount = document.getElementById("show-amount"); let v = amount.value + amount.fraction / 1e6;
$_('merchant-name').innerText = contract.merchant.name; return `${v.toFixed(2)} ${amount.currency}`;
}
function clone(obj) {
// This is faster than it looks ...
return JSON.parse(JSON.stringify(obj));
} }
Handlebars.registerHelper('prettyAmount', function(amount) { export function main() {
let v = amount.value + amount.fraction / 10e6; let url = URI(document.location.href);
return v.toFixed(2) + " " + amount.currency; let query: any = URI.parseQuery(url.query());
});
document.addEventListener("DOMContentLoaded", (e) => {
let offer = JSON.parse(query.offer); let offer = JSON.parse(query.offer);
console.dir(offer); console.dir(offer);
let contract = offer.contract;
let source = $_("contract-template").innerHTML; var Contract = {
let template = Handlebars.compile(source); view(ctrl) {
$_("render-contract").innerHTML = template(offer.contract); return [
m("p",
i18n`Hello, this is the wallet. The merchant "${contract.merchant.name}"
wants to enter a contract over ${prettyAmount(contract.amount)}
with you.`),
m("p",
i18n`The contract contains the following products:`),
m('ul',
_.map(contract.products,
(p: any) => m("li",
`${p.description}: ${prettyAmount(p.price)}`))),
m("button", {onclick: doPayment}, i18n`Confirm Payment`)
];
}
};
document.getElementById("confirm-pay").addEventListener("click", (e) => { m.mount(document.getElementById("contract"), Contract);
console.log("Query:", JSON.stringify(query));
function doPayment() {
let d = { let d = {
offer: JSON.parse(query.offer), offer
merchantPageUrl: query.merchantPageUrl
}; };
chrome.runtime.sendMessage({type:'confirm-pay', detail: d}, (resp) => { chrome.runtime.sendMessage({type: 'confirm-pay', detail: d}, (resp) => {
if (!resp.success) { if (!resp.success) {
let source = $_("error-template").innerHTML; console.log("confirm-pay error", JSON.stringify(resp));
let template = Handlebars.compile(source);
$_("status").innerHTML = template(resp);
return; return;
} }
document.location.href = URI(d.offer.exec_url) let c = d.offer.contract;
.absoluteTo(query.merchantPageUrl) console.log("contract", c);
.addQuery({H_contract: d.offer.H_contract}) document.location.href = substituteFulfillmentUrl(c.fulfillment_url, offer);
.href();
}); });
}); }
}); }

View File

@ -4,8 +4,8 @@
<head> <head>
<title>Taler Wallet: Select Taler Provider</title> <title>Taler Wallet: Select Taler Provider</title>
<script src="../lib/vendor/URI.js"></script> <script src="../lib/vendor/URI.js"></script>
<script src="../lib/polyfill-react.js"></script> <script src="../lib/vendor/system-csp-production.src.js"></script>
<script src="confirm-create-reserve.js"></script> <script src="../lib/module-trampoline.js"></script>
<link rel="stylesheet" type="text/css" href="../style/wallet.css"> <link rel="stylesheet" type="text/css" href="../style/wallet.css">
</head> </head>

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
(C) 2015 GNUnet e.V. (C) 2015-2016 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -13,27 +13,26 @@
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/ */
"use strict"; System.register([], function(exports_1) {
var ConfirmCreateReserve; "use strict";
(function (ConfirmCreateReserve) { function main() {
var url = URI(document.location.href); function updateAmount() {
var query = URI.parseQuery(url.query()); var showAmount = document.getElementById("show-amount");
function updateAmount() { console.log("Query is " + JSON.stringify(query));
var showAmount = document.getElementById("show-amount"); var s = query.amount_str;
console.log("Query is " + JSON.stringify(query)); if (!s) {
var s = query.amount_str; document.body.innerHTML = "Oops, something went wrong.";
if (!s) { return;
document.body.innerHTML = "Oops, something went wrong."; }
return; showAmount.textContent = s;
} }
showAmount.textContent = s; var url = URI(document.location.href);
} var query = URI.parseQuery(url.query());
document.addEventListener("DOMContentLoaded", function (e) {
updateAmount(); updateAmount();
document.getElementById("confirm").addEventListener("click", function (e) { document.getElementById("confirm").addEventListener("click", function (e) {
var d = Object.assign({}, query); var d = Object.assign({}, query);
d.mint = document.getElementById('mint-url').value; d.mint = document.getElementById('mint-url').value;
chrome.runtime.sendMessage({ type: 'confirm-reserve', detail: d }, function (resp) { var cb = function (resp) {
if (resp.success === true) { if (resp.success === true) {
document.location.href = resp.backlink; document.location.href = resp.backlink;
} }
@ -41,8 +40,15 @@ var ConfirmCreateReserve;
document.body.innerHTML = document.body.innerHTML =
"Oops, something went wrong. It looks like the bank could not\n transfer funds to the mint. Please go back to your bank's website\n to check what happened."; "Oops, something went wrong. It looks like the bank could not\n transfer funds to the mint. Please go back to your bank's website\n to check what happened.";
} }
}); };
chrome.runtime.sendMessage({ type: 'confirm-reserve', detail: d }, cb);
}); });
}); }
})(ConfirmCreateReserve || (ConfirmCreateReserve = {})); exports_1("main", main);
return {
setters:[],
execute: function() {
}
}
});
//# sourceMappingURL=confirm-create-reserve.js.map //# sourceMappingURL=confirm-create-reserve.js.map

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
(C) 2015 GNUnet e.V. (C) 2015-2016 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the 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 terms of the GNU General Public License as published by the Free Software
@ -16,11 +16,8 @@
"use strict"; "use strict";
namespace ConfirmCreateReserve {
let url = URI(document.location.href);
let query: any = URI.parseQuery(url.query());
export function main() {
function updateAmount() { function updateAmount() {
let showAmount = document.getElementById("show-amount"); let showAmount = document.getElementById("show-amount");
console.log("Query is " + JSON.stringify(query)); console.log("Query is " + JSON.stringify(query));
@ -32,26 +29,25 @@ namespace ConfirmCreateReserve {
showAmount.textContent = s; showAmount.textContent = s;
} }
let url = URI(document.location.href);
let query: any = URI.parseQuery(url.query());
document.addEventListener("DOMContentLoaded", (e) => { updateAmount();
updateAmount();
document.getElementById("confirm").addEventListener("click", (e) => { document.getElementById("confirm").addEventListener("click", (e) => {
let d = Object.assign({}, query); let d = Object.assign({}, query);
d.mint = (document.getElementById('mint-url') as HTMLInputElement).value; d.mint = (document.getElementById('mint-url') as HTMLInputElement).value;
chrome.runtime.sendMessage({type:'confirm-reserve', detail: d},
(resp) => { const cb = (resp) => {
if (resp.success === true) { if (resp.success === true) {
document.location.href = resp.backlink; document.location.href = resp.backlink;
} else { } else {
document.body.innerHTML = document.body.innerHTML =
`Oops, something went wrong. It looks like the bank could not `Oops, something went wrong. It looks like the bank could not
transfer funds to the mint. Please go back to your bank's website transfer funds to the mint. Please go back to your bank's website
to check what happened.`; to check what happened.`;
} }
}); };
chrome.runtime.sendMessage({type: 'confirm-reserve', detail: d}, cb);
});
}); });
} }

View File

@ -6,7 +6,8 @@
<script src="../lib/vendor/mithril.js"></script> <script src="../lib/vendor/mithril.js"></script>
<script src="../lib/i18n.js"></script> <script src="../lib/i18n.js"></script>
<script src="../lib/vendor/lodash.core.min.js"></script> <script src="../lib/vendor/lodash.core.min.js"></script>
<script src="popup.js"></script> <script src="../lib/vendor/system-csp-production.src.js"></script>
<script src="../lib/module-trampoline.js"></script>
</head> </head>
<body> <body>
<div id="nav"></div> <div id="nav"></div>

View File

@ -20,11 +20,12 @@
"use strict"; "use strict";
declare var m: any; declare var m: any;
declare var i18n: any; declare var i18n: any;
document.addEventListener("DOMContentLoaded", function(event) {
export function main() {
console.log("popup main");
m.route.mode = "hash"; m.route.mode = "hash";
m.route(document.getElementById("content"), "/balance", { m.route(document.getElementById("content"), "/balance", {
"/balance": WalletBalance, "/balance": WalletBalance,
@ -32,7 +33,9 @@ document.addEventListener("DOMContentLoaded", function(event) {
"/debug": WalletDebug, "/debug": WalletDebug,
}); });
m.mount(document.getElementById("nav"), WalletNavBar); m.mount(document.getElementById("nav"), WalletNavBar);
}); }
console.log("this is popup");
function makeTab(target, name) { function makeTab(target, name) {
@ -84,7 +87,9 @@ var WalletBalance = {
if (listing.length > 0) { if (listing.length > 0) {
return listing; return listing;
} }
let link = m("a[href=https://demo.taler.net]", {config: openInExtension}, i18n`free KUDOS`); let link = m("a[href=https://demo.taler.net]",
{config: openInExtension},
i18n`free KUDOS`);
return i18n.parts`You have no balance to show. Want to get some ${link}?`; return i18n.parts`You have no balance to show. Want to get some ${link}?`;
} }
}; };
@ -102,7 +107,7 @@ function formatAmount(amount) {
} }
function abbrevKey(s: string) { function abbrevKey(s: string) {
return m("span.abbrev", {title: s}, (s.slice(0,5) + "..")) return m("span.abbrev", {title: s}, (s.slice(0, 5) + ".."))
} }
@ -112,7 +117,8 @@ function formatHistoryItem(historyItem) {
switch (historyItem.type) { switch (historyItem.type) {
case "create-reserve": case "create-reserve":
return m("p", return m("p",
i18n.parts`Created reserve (${abbrevKey(d.reservePub)}) of ${formatAmount(d.requestedAmount)} at ${formatTimestamp( i18n.parts`Created reserve (${abbrevKey(d.reservePub)}) of ${formatAmount(
d.requestedAmount)} at ${formatTimestamp(
t)}`); t)}`);
case "withdraw": case "withdraw":
return m("p", return m("p",
@ -155,17 +161,20 @@ var WalletHistory = {
}; };
function reload() {
try {
chrome.runtime.reload();
window.close();
} catch (e) {
// Functionality missing in firefox, ignore!
}
}
function confirmReset() { function confirmReset() {
if (confirm("Do you want to IRREVOCABLY DESTROY everything inside your" + if (confirm("Do you want to IRREVOCABLY DESTROY everything inside your" +
" wallet and LOSE ALL YOUR COINS?")) { " wallet and LOSE ALL YOUR COINS?")) {
chrome.runtime.sendMessage({type: "reset"}); chrome.runtime.sendMessage({type: "reset"});
window.close(); window.close();
try {
chrome.runtime.reload();
} catch (e) {
// Functionality missing in firefox, ignore!
}
} }
} }
@ -173,15 +182,25 @@ function confirmReset() {
var WalletDebug = { var WalletDebug = {
view() { view() {
return [ return [
m("button", {onclick: openWalletAsTab}, "wallet tab"), m("button",
m("button", {onclick: confirmReset}, "reset") {onclick: openExtensionPage("popup/popup.html")},
"wallet tab"),
m("button",
{onclick: openExtensionPage("pages/show-db.html")},
"show db"),
m("br"),
m("button", {onclick: confirmReset}, "reset"),
m("button", {onclick: reload}, "reload chrome extension"),
] ]
} }
}; };
function openWalletAsTab() { function openExtensionPage(page) {
chrome.tabs.create({ return function() {
"url": chrome.extension.getURL("popup/popup.html") chrome.tabs.create({
}); "url": chrome.extension.getURL(page)
});
}
} }

View File

@ -10,6 +10,7 @@
"files": [ "files": [
"lib/i18n.ts", "lib/i18n.ts",
"lib/refs.ts", "lib/refs.ts",
"lib/web-common.ts",
"lib/wallet/checkable.ts", "lib/wallet/checkable.ts",
"lib/wallet/db.ts", "lib/wallet/db.ts",
"lib/wallet/emscriptif.ts", "lib/wallet/emscriptif.ts",