refactoring; make wallet follow new bank protocol
This commit is contained in:
parent
47f2084706
commit
164d5f20c3
@ -14,7 +14,7 @@
|
|||||||
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/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AmountJson} from "./wallet";
|
import {AmountJson} from "./types";
|
||||||
import * as EmscWrapper from "../emscripten/emsc";
|
import * as EmscWrapper from "../emscripten/emsc";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,7 +14,13 @@
|
|||||||
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/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AmountJson} from "./wallet/wallet";
|
|
||||||
|
/**
|
||||||
|
* Smaller helper functions that do not depend
|
||||||
|
* on the emscripten machinery.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {AmountJson} from "./types";
|
||||||
|
|
||||||
export function substituteFulfillmentUrl(url: string, vars) {
|
export function substituteFulfillmentUrl(url: string, vars) {
|
||||||
url = url.replace("${H_contract}", vars.H_contract);
|
url = url.replace("${H_contract}", vars.H_contract);
|
||||||
@ -22,7 +28,38 @@ export function substituteFulfillmentUrl(url: string, vars) {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function amountToPretty(amount: AmountJson): string {
|
export function amountToPretty(amount: AmountJson): string {
|
||||||
let x = amount.value + amount.fraction / 1e6;
|
let x = amount.value + amount.fraction / 1e6;
|
||||||
return `${x} ${amount.currency}`;
|
return `${x} ${amount.currency}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Canonicalize a base url, typically for the mint.
|
||||||
|
*
|
||||||
|
* See http://api.taler.net/wallet.html#general
|
||||||
|
*/
|
||||||
|
export function canonicalizeBaseUrl(url) {
|
||||||
|
let x = new URI(url);
|
||||||
|
if (!x.protocol()) {
|
||||||
|
x.protocol("https");
|
||||||
|
}
|
||||||
|
x.path(x.path() + "/").normalizePath();
|
||||||
|
x.fragment();
|
||||||
|
x.query();
|
||||||
|
return x.href()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function parsePrettyAmount(pretty: string): AmountJson {
|
||||||
|
const res = /([0-9]+)(.[0-9]+)?\s*(\w+)/.exec(pretty);
|
||||||
|
if (!res) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
value: parseInt(res[1], 10),
|
||||||
|
fraction: res[2] ? (parseFloat(`0.${res[2]}`) * 1e-6) : 0,
|
||||||
|
currency: res[3]
|
||||||
|
}
|
||||||
|
}
|
56
extension/lib/wallet/types.ts
Normal file
56
extension/lib/wallet/types.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
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, If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common types that are used by Taler.
|
||||||
|
*
|
||||||
|
* Note most types are defined in wallet.ts, types that
|
||||||
|
* are defined in types.ts are intended to be used by components
|
||||||
|
* that do not depend on the whole wallet implementation (which depends on
|
||||||
|
* emscripten).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Checkable} from "./checkable";
|
||||||
|
|
||||||
|
@Checkable.Class
|
||||||
|
export class AmountJson {
|
||||||
|
@Checkable.Number
|
||||||
|
value: number;
|
||||||
|
|
||||||
|
@Checkable.Number
|
||||||
|
fraction: number;
|
||||||
|
|
||||||
|
@Checkable.String
|
||||||
|
currency: string;
|
||||||
|
|
||||||
|
static checked: (obj: any) => AmountJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Checkable.Class
|
||||||
|
export class CreateReserveResponse {
|
||||||
|
/**
|
||||||
|
* Mint URL where the bank should create the reserve.
|
||||||
|
* The URL is canonicalized in the response.
|
||||||
|
*/
|
||||||
|
@Checkable.String
|
||||||
|
mint: string;
|
||||||
|
|
||||||
|
@Checkable.String
|
||||||
|
reservePub: string;
|
||||||
|
|
||||||
|
static checked: (obj: any) => CreateReserveResponse;
|
||||||
|
}
|
@ -22,9 +22,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as native from "./emscriptif";
|
import * as native from "./emscriptif";
|
||||||
|
import {AmountJson, CreateReserveResponse} from "./types";
|
||||||
import {HttpResponse, RequestException} from "./http";
|
import {HttpResponse, RequestException} from "./http";
|
||||||
import {Query} from "./query";
|
import {Query} from "./query";
|
||||||
import {Checkable} from "./checkable";
|
import {Checkable} from "./checkable";
|
||||||
|
import {canonicalizeBaseUrl} from "./helpers";
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
@ -73,21 +75,6 @@ export interface Coin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Checkable.Class
|
|
||||||
export class AmountJson {
|
|
||||||
@Checkable.Number
|
|
||||||
value: number;
|
|
||||||
|
|
||||||
@Checkable.Number
|
|
||||||
fraction: number;
|
|
||||||
|
|
||||||
@Checkable.String
|
|
||||||
currency: string;
|
|
||||||
|
|
||||||
static checked: (obj: any) => AmountJson;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Checkable.Class
|
@Checkable.Class
|
||||||
export class CreateReserveRequest {
|
export class CreateReserveRequest {
|
||||||
/**
|
/**
|
||||||
@ -106,22 +93,6 @@ export class CreateReserveRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Checkable.Class
|
|
||||||
export class CreateReserveResponse {
|
|
||||||
/**
|
|
||||||
* Mint URL where the bank should create the reserve.
|
|
||||||
* The URL is canonicalized in the response.
|
|
||||||
*/
|
|
||||||
@Checkable.String
|
|
||||||
mint: string;
|
|
||||||
|
|
||||||
@Checkable.String
|
|
||||||
reservePub: string;
|
|
||||||
|
|
||||||
static checked: (obj: any) => CreateReserveResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Checkable.Class
|
@Checkable.Class
|
||||||
export class ConfirmReserveRequest {
|
export class ConfirmReserveRequest {
|
||||||
/**
|
/**
|
||||||
@ -270,34 +241,6 @@ function isWithdrawableDenom(d: Denomination) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See http://api.taler.net/wallet.html#general
|
|
||||||
*/
|
|
||||||
function canonicalizeBaseUrl(url) {
|
|
||||||
let x = new URI(url);
|
|
||||||
if (!x.protocol()) {
|
|
||||||
x.protocol("https");
|
|
||||||
}
|
|
||||||
x.path(x.path() + "/").normalizePath();
|
|
||||||
x.fragment();
|
|
||||||
x.query();
|
|
||||||
return x.href()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function parsePrettyAmount(pretty: string): AmountJson {
|
|
||||||
const res = /([0-9]+)(.[0-9]+)?\s*(\w+)/.exec(pretty);
|
|
||||||
if (!res) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
value: parseInt(res[1], 10),
|
|
||||||
fraction: res[2] ? (parseFloat(`0.${res[2]}`) * 1e-6) : 0,
|
|
||||||
currency: res[3]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
interface HttpRequestLibrary {
|
interface HttpRequestLibrary {
|
||||||
req(method: string,
|
req(method: string,
|
||||||
url: string|uri.URI,
|
url: string|uri.URI,
|
||||||
|
@ -13,11 +13,11 @@
|
|||||||
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/>
|
||||||
*/
|
*/
|
||||||
System.register(["../lib/web-common"], function(exports_1, context_1) {
|
System.register(["../lib/wallet/helpers"], function(exports_1, context_1) {
|
||||||
/// <reference path="../lib/decl/handlebars/handlebars.d.ts" />
|
/// <reference path="../lib/decl/handlebars/handlebars.d.ts" />
|
||||||
"use strict";
|
"use strict";
|
||||||
var __moduleName = context_1 && context_1.id;
|
var __moduleName = context_1 && context_1.id;
|
||||||
var web_common_1;
|
var helpers_1;
|
||||||
function prettyAmount(amount) {
|
function prettyAmount(amount) {
|
||||||
var v = amount.value + amount.fraction / 1e6;
|
var v = amount.value + amount.fraction / 1e6;
|
||||||
return v.toFixed(2) + " " + amount.currency;
|
return v.toFixed(2) + " " + amount.currency;
|
||||||
@ -55,15 +55,15 @@ System.register(["../lib/web-common"], function(exports_1, context_1) {
|
|||||||
}
|
}
|
||||||
var c = d.offer.contract;
|
var c = d.offer.contract;
|
||||||
console.log("contract", c);
|
console.log("contract", c);
|
||||||
document.location.href = web_common_1.substituteFulfillmentUrl(c.fulfillment_url, offer);
|
document.location.href = helpers_1.substituteFulfillmentUrl(c.fulfillment_url, offer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports_1("main", main);
|
exports_1("main", main);
|
||||||
return {
|
return {
|
||||||
setters:[
|
setters:[
|
||||||
function (web_common_1_1) {
|
function (helpers_1_1) {
|
||||||
web_common_1 = web_common_1_1;
|
helpers_1 = helpers_1_1;
|
||||||
}],
|
}],
|
||||||
execute: function() {
|
execute: function() {
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
/// <reference path="../lib/decl/handlebars/handlebars.d.ts" />
|
/// <reference path="../lib/decl/handlebars/handlebars.d.ts" />
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import {substituteFulfillmentUrl} from "../lib/web-common";
|
import {substituteFulfillmentUrl} from "../lib/wallet/helpers";
|
||||||
|
|
||||||
declare var m: any;
|
declare var m: any;
|
||||||
|
|
||||||
|
@ -4,6 +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/i18n.js"></script>
|
||||||
|
<script src="../lib/vendor/mithril.js"></script>
|
||||||
<script src="../lib/vendor/system-csp-production.src.js"></script>
|
<script src="../lib/vendor/system-csp-production.src.js"></script>
|
||||||
<script src="../lib/module-trampoline.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">
|
||||||
@ -22,27 +24,7 @@
|
|||||||
<section id="main">
|
<section id="main">
|
||||||
|
|
||||||
<article>
|
<article>
|
||||||
<p>
|
<div id="mint-selection"></div>
|
||||||
You asked to withdraw <span id="show-amount">(loading...)</span> from your
|
|
||||||
bank account.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Please specify the base URL of the Taler mint you want to use. The Taler
|
|
||||||
mint will process the payments, possibly for a fee. The mint underwrites
|
|
||||||
electronic coins and will hold matching funds in reserve in its bank
|
|
||||||
account. Mints are expected to be regularly audited by a trusted party to
|
|
||||||
ensure that they have sufficient reserves to cover all outstanding
|
|
||||||
obligations.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="formish">
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="mint-url">Mint URL</label>
|
|
||||||
<input class="url" id="mint-url" type="text"
|
|
||||||
value="http://mint.demo.taler.net/"/>
|
|
||||||
</div>
|
|
||||||
<button id="confirm">Confirm Mint Selection</button>
|
|
||||||
</div>
|
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
@ -13,69 +13,176 @@
|
|||||||
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/>
|
||||||
*/
|
*/
|
||||||
System.register(["../lib/web-common", "../lib/wallet/wallet"], function(exports_1, context_1) {
|
System.register(["../lib/wallet/helpers", "../lib/wallet/types"], function(exports_1, context_1) {
|
||||||
"use strict";
|
"use strict";
|
||||||
var __moduleName = context_1 && context_1.id;
|
var __moduleName = context_1 && context_1.id;
|
||||||
var web_common_1, wallet_1;
|
var helpers_1, types_1;
|
||||||
|
var DelayTimer, Controller;
|
||||||
function main() {
|
function main() {
|
||||||
function updateAmount() {
|
|
||||||
var showAmount = document.getElementById("show-amount");
|
|
||||||
console.log("Query is " + JSON.stringify(query));
|
|
||||||
var amount = wallet_1.AmountJson.checked(JSON.parse(query.amount));
|
|
||||||
showAmount.textContent = web_common_1.amountToPretty(amount);
|
|
||||||
}
|
|
||||||
var url = URI(document.location.href);
|
var url = URI(document.location.href);
|
||||||
var query = URI.parseQuery(url.query());
|
var query = URI.parseQuery(url.query());
|
||||||
updateAmount();
|
var amount = types_1.AmountJson.checked(JSON.parse(query.amount));
|
||||||
document.getElementById("confirm").addEventListener("click", function (e) {
|
var callback_url = query.callback_url;
|
||||||
var d = {
|
var MintSelection = {
|
||||||
mint: document.getElementById('mint-url').value,
|
controller: function () { return new Controller(); },
|
||||||
amount: JSON.parse(query.amount)
|
view: function (ctrl) {
|
||||||
|
var controls = [];
|
||||||
|
var mx = function () {
|
||||||
|
var args = [];
|
||||||
|
for (var _i = 0; _i < arguments.length; _i++) {
|
||||||
|
args[_i - 0] = arguments[_i];
|
||||||
|
}
|
||||||
|
return controls.push(m.apply(void 0, args));
|
||||||
};
|
};
|
||||||
if (!d.mint) {
|
mx("p", (_a = ["The bank wants to create a reserve over ", "."], _a.raw = ["The bank wants to create a reserve over ", "."], i18n(_a, helpers_1.amountToPretty(amount))));
|
||||||
// FIXME: indicate error instead!
|
mx("input.url", {
|
||||||
throw Error("mint missing");
|
type: "text",
|
||||||
|
spellcheck: false,
|
||||||
|
oninput: m.withAttr("value", ctrl.onUrlChanged.bind(ctrl)),
|
||||||
|
});
|
||||||
|
if (ctrl.isValidMint) {
|
||||||
|
mx("button", {
|
||||||
|
onclick: function () { return ctrl.confirmReserve(ctrl.url, amount, callback_url); }
|
||||||
|
}, "Confirm mint selection");
|
||||||
}
|
}
|
||||||
if (!d.amount) {
|
if (ctrl.errorString) {
|
||||||
// FIXME: indicate error instead!
|
mx("p", ctrl.errorString);
|
||||||
throw Error("amount missing");
|
|
||||||
}
|
}
|
||||||
|
return m("div", controls);
|
||||||
|
var _a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
m.mount(document.getElementById("mint-selection"), MintSelection);
|
||||||
|
}
|
||||||
|
exports_1("main", main);
|
||||||
|
return {
|
||||||
|
setters:[
|
||||||
|
function (helpers_1_1) {
|
||||||
|
helpers_1 = helpers_1_1;
|
||||||
|
},
|
||||||
|
function (types_1_1) {
|
||||||
|
types_1 = types_1_1;
|
||||||
|
}],
|
||||||
|
execute: function() {
|
||||||
|
"use strict";
|
||||||
|
/**
|
||||||
|
* Execute something after a delay, with the possibility
|
||||||
|
* to reset the delay.
|
||||||
|
*/
|
||||||
|
DelayTimer = (function () {
|
||||||
|
function DelayTimer(ms, f) {
|
||||||
|
this.timerId = null;
|
||||||
|
this.f = f;
|
||||||
|
this.ms = ms;
|
||||||
|
}
|
||||||
|
DelayTimer.prototype.bump = function () {
|
||||||
|
var _this = this;
|
||||||
|
if (this.timerId !== null) {
|
||||||
|
window.clearTimeout(this.timerId);
|
||||||
|
}
|
||||||
|
var handler = function () {
|
||||||
|
_this.f();
|
||||||
|
};
|
||||||
|
this.timerId = window.setTimeout(handler, this.ms);
|
||||||
|
};
|
||||||
|
return DelayTimer;
|
||||||
|
}());
|
||||||
|
Controller = (function () {
|
||||||
|
function Controller() {
|
||||||
|
var _this = this;
|
||||||
|
this.url = null;
|
||||||
|
this.errorString = null;
|
||||||
|
this.isValidMint = false;
|
||||||
|
this.update();
|
||||||
|
this.timer = new DelayTimer(800, function () { return _this.update(); });
|
||||||
|
}
|
||||||
|
Controller.prototype.update = function () {
|
||||||
|
var _this = this;
|
||||||
|
var doUpdate = function () {
|
||||||
|
if (!_this.url) {
|
||||||
|
_this.errorString = (_a = ["Please enter a URL"], _a.raw = ["Please enter a URL"], i18n(_a));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_this.errorString = null;
|
||||||
|
var parsedUrl = URI(_this.url);
|
||||||
|
if (parsedUrl.is("relative")) {
|
||||||
|
_this.errorString = (_b = ["The URL you've entered is not valid (must be absolute)"], _b.raw = ["The URL you've entered is not valid (must be absolute)"], i18n(_b));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var keysUrl = URI("/keys").absoluteTo(helpers_1.canonicalizeBaseUrl(_this.url));
|
||||||
|
console.log("requesting keys from '" + keysUrl + "'");
|
||||||
|
_this.request = new XMLHttpRequest();
|
||||||
|
_this.request.onreadystatechange = function () {
|
||||||
|
if (_this.request.readyState == XMLHttpRequest.DONE) {
|
||||||
|
switch (_this.request.status) {
|
||||||
|
case 200:
|
||||||
|
_this.isValidMint = true;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
_this.errorString = "unknown request error";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_this.errorString = "request failed with status " + _this.request.status;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m.redraw();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_this.request.open("get", keysUrl.href());
|
||||||
|
_this.request.send();
|
||||||
|
var _a, _b;
|
||||||
|
};
|
||||||
|
doUpdate();
|
||||||
|
m.redraw();
|
||||||
|
console.log("got update");
|
||||||
|
};
|
||||||
|
Controller.prototype.reset = function () {
|
||||||
|
this.isValidMint = false;
|
||||||
|
this.errorString = null;
|
||||||
|
if (this.request) {
|
||||||
|
this.request.abort();
|
||||||
|
this.request = null;
|
||||||
|
}
|
||||||
|
m.redraw();
|
||||||
|
};
|
||||||
|
Controller.prototype.confirmReserve = function (mint, amount, callback_url) {
|
||||||
|
var _this = this;
|
||||||
|
var d = { mint: mint, amount: amount };
|
||||||
var cb = function (rawResp) {
|
var cb = function (rawResp) {
|
||||||
if (!rawResp) {
|
if (!rawResp) {
|
||||||
throw Error("empty response");
|
throw Error("empty response");
|
||||||
}
|
}
|
||||||
if (!rawResp.error) {
|
if (!rawResp.error) {
|
||||||
var resp = wallet_1.CreateReserveResponse.checked(rawResp);
|
var resp = types_1.CreateReserveResponse.checked(rawResp);
|
||||||
var q = {
|
var q = {
|
||||||
mint: resp.mint,
|
mint: resp.mint,
|
||||||
reserve_pub: resp.reservePub,
|
reserve_pub: resp.reservePub,
|
||||||
amount: query.amount,
|
amount_value: amount.value,
|
||||||
|
amount_fraction: amount.fraction,
|
||||||
|
amount_currency: amount.currency,
|
||||||
};
|
};
|
||||||
var url_1 = URI(query.callback_url).addQuery(q);
|
var url = URI(callback_url).addQuery(q);
|
||||||
if (!url_1.is("absolute")) {
|
if (!url.is("absolute")) {
|
||||||
throw Error("callback url is not absolute");
|
throw Error("callback url is not absolute");
|
||||||
}
|
}
|
||||||
document.location.href = url_1.href();
|
console.log("going to", url.href());
|
||||||
|
document.location.href = url.href();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
document.body.innerHTML =
|
_this.reset();
|
||||||
"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.";
|
_this.errorString = ("Oops, something went wrong." +
|
||||||
|
("The wallet responded with error status (" + rawResp.error + ")."));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
chrome.runtime.sendMessage({ type: 'create-reserve', detail: d }, cb);
|
chrome.runtime.sendMessage({ type: 'create-reserve', detail: d }, cb);
|
||||||
});
|
};
|
||||||
}
|
Controller.prototype.onUrlChanged = function (url) {
|
||||||
exports_1("main", main);
|
this.reset();
|
||||||
return {
|
this.url = url;
|
||||||
setters:[
|
this.timer.bump();
|
||||||
function (web_common_1_1) {
|
};
|
||||||
web_common_1 = web_common_1_1;
|
return Controller;
|
||||||
},
|
}());
|
||||||
function (wallet_1_1) {
|
|
||||||
wallet_1 = wallet_1_1;
|
|
||||||
}],
|
|
||||||
execute: function() {
|
|
||||||
"use strict";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -14,40 +14,107 @@
|
|||||||
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/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {amountToPretty} from "../lib/web-common";
|
import {amountToPretty, canonicalizeBaseUrl} from "../lib/wallet/helpers";
|
||||||
import {AmountJson, CreateReserveResponse} from "../lib/wallet/wallet";
|
import {AmountJson, CreateReserveResponse} from "../lib/wallet/types";
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
declare var m: any;
|
||||||
|
|
||||||
export function main() {
|
|
||||||
function updateAmount() {
|
/**
|
||||||
let showAmount = document.getElementById("show-amount");
|
* Execute something after a delay, with the possibility
|
||||||
console.log("Query is " + JSON.stringify(query));
|
* to reset the delay.
|
||||||
let amount = AmountJson.checked(JSON.parse(query.amount));
|
*/
|
||||||
showAmount.textContent = amountToPretty(amount);
|
class DelayTimer {
|
||||||
|
ms: number;
|
||||||
|
f;
|
||||||
|
timerId: number = null;
|
||||||
|
|
||||||
|
constructor(ms: number, f) {
|
||||||
|
this.f = f;
|
||||||
|
this.ms = ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = URI(document.location.href);
|
bump() {
|
||||||
let query: any = URI.parseQuery(url.query());
|
if (this.timerId !== null) {
|
||||||
|
window.clearTimeout(this.timerId);
|
||||||
|
}
|
||||||
|
const handler = () => {
|
||||||
|
this.f();
|
||||||
|
};
|
||||||
|
this.timerId = window.setTimeout(handler, this.ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateAmount();
|
|
||||||
|
|
||||||
document.getElementById("confirm").addEventListener("click", (e) => {
|
class Controller {
|
||||||
const d = {
|
url = null;
|
||||||
mint: (document.getElementById('mint-url') as HTMLInputElement).value,
|
errorString = null;
|
||||||
amount: JSON.parse(query.amount)
|
isValidMint = false;
|
||||||
|
private timer: DelayTimer;
|
||||||
|
private request: XMLHttpRequest;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.update();
|
||||||
|
this.timer = new DelayTimer(800, () => this.update());
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
const doUpdate = () => {
|
||||||
|
if (!this.url) {
|
||||||
|
this.errorString = i18n`Please enter a URL`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.errorString = null;
|
||||||
|
let parsedUrl = URI(this.url);
|
||||||
|
if (parsedUrl.is("relative")) {
|
||||||
|
this.errorString = i18n`The URL you've entered is not valid (must be absolute)`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const keysUrl = URI("/keys").absoluteTo(canonicalizeBaseUrl(this.url));
|
||||||
|
|
||||||
|
console.log(`requesting keys from '${keysUrl}'`);
|
||||||
|
|
||||||
|
this.request = new XMLHttpRequest();
|
||||||
|
this.request.onreadystatechange = () => {
|
||||||
|
if (this.request.readyState == XMLHttpRequest.DONE) {
|
||||||
|
switch (this.request.status) {
|
||||||
|
case 200:
|
||||||
|
this.isValidMint = true;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
this.errorString = `unknown request error`;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.errorString = `request failed with status ${this.request.status}`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m.redraw();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.request.open("get", keysUrl.href());
|
||||||
|
this.request.send();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!d.mint) {
|
doUpdate();
|
||||||
// FIXME: indicate error instead!
|
m.redraw();
|
||||||
throw Error("mint missing");
|
console.log("got update");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!d.amount) {
|
reset() {
|
||||||
// FIXME: indicate error instead!
|
this.isValidMint = false;
|
||||||
throw Error("amount missing");
|
this.errorString = null;
|
||||||
|
if (this.request) {
|
||||||
|
this.request.abort();
|
||||||
|
this.request = null;
|
||||||
|
}
|
||||||
|
m.redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
confirmReserve(mint: string, amount: AmountJson, callback_url: string) {
|
||||||
|
const d = {mint, amount};
|
||||||
const cb = (rawResp) => {
|
const cb = (rawResp) => {
|
||||||
if (!rawResp) {
|
if (!rawResp) {
|
||||||
throw Error("empty response");
|
throw Error("empty response");
|
||||||
@ -57,20 +124,72 @@ export function main() {
|
|||||||
let q = {
|
let q = {
|
||||||
mint: resp.mint,
|
mint: resp.mint,
|
||||||
reserve_pub: resp.reservePub,
|
reserve_pub: resp.reservePub,
|
||||||
amount: query.amount,
|
amount_value: amount.value,
|
||||||
|
amount_fraction: amount.fraction,
|
||||||
|
amount_currency: amount.currency,
|
||||||
};
|
};
|
||||||
let url = URI(query.callback_url).addQuery(q);
|
let url = URI(callback_url).addQuery(q);
|
||||||
if (!url.is("absolute")) {
|
if (!url.is("absolute")) {
|
||||||
throw Error("callback url is not absolute");
|
throw Error("callback url is not absolute");
|
||||||
}
|
}
|
||||||
|
console.log("going to", url.href());
|
||||||
document.location.href = url.href();
|
document.location.href = url.href();
|
||||||
} else {
|
} else {
|
||||||
document.body.innerHTML =
|
this.reset();
|
||||||
`Oops, something went wrong. It looks like the bank could not
|
this.errorString = (
|
||||||
transfer funds to the mint. Please go back to your bank's website
|
`Oops, something went wrong.` +
|
||||||
to check what happened.`;
|
`The wallet responded with error status (${rawResp.error}).`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
chrome.runtime.sendMessage({type: 'create-reserve', detail: d}, cb);
|
chrome.runtime.sendMessage({type: 'create-reserve', detail: d}, cb);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
onUrlChanged(url: string) {
|
||||||
|
this.reset();
|
||||||
|
this.url = url;
|
||||||
|
this.timer.bump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
const url = URI(document.location.href);
|
||||||
|
const query: any = URI.parseQuery(url.query());
|
||||||
|
const amount = AmountJson.checked(JSON.parse(query.amount));
|
||||||
|
const callback_url = query.callback_url;
|
||||||
|
|
||||||
|
var MintSelection = {
|
||||||
|
controller: () => new Controller(),
|
||||||
|
view(ctrl: Controller) {
|
||||||
|
let controls = [];
|
||||||
|
let mx = (...args) => controls.push(m(...args));
|
||||||
|
|
||||||
|
mx("p",
|
||||||
|
i18n`The bank wants to create a reserve over ${amountToPretty(
|
||||||
|
amount)}.`);
|
||||||
|
mx("input.url",
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
spellcheck: false,
|
||||||
|
oninput: m.withAttr("value", ctrl.onUrlChanged.bind(ctrl)),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ctrl.isValidMint) {
|
||||||
|
mx("button", {
|
||||||
|
onclick: () => ctrl.confirmReserve(ctrl.url,
|
||||||
|
amount,
|
||||||
|
callback_url)
|
||||||
|
},
|
||||||
|
"Confirm mint selection");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctrl.errorString) {
|
||||||
|
mx("p", ctrl.errorString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m("div", controls);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
m.mount(document.getElementById("mint-selection"), MintSelection);
|
||||||
}
|
}
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import {substituteFulfillmentUrl} from "../lib/web-common";
|
import {substituteFulfillmentUrl} from "../lib/wallet/helpers";
|
||||||
|
|
||||||
declare var m: any;
|
declare var m: any;
|
||||||
declare var i18n: any;
|
declare var i18n: any;
|
||||||
|
@ -12,12 +12,13 @@
|
|||||||
"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",
|
||||||
|
"lib/wallet/helpers.ts",
|
||||||
"lib/wallet/http.ts",
|
"lib/wallet/http.ts",
|
||||||
"lib/wallet/query.ts",
|
"lib/wallet/query.ts",
|
||||||
|
"lib/wallet/types.ts",
|
||||||
"lib/wallet/wallet.ts",
|
"lib/wallet/wallet.ts",
|
||||||
"lib/wallet/wxmessaging.ts",
|
"lib/wallet/wxmessaging.ts",
|
||||||
"background/main.ts",
|
"background/main.ts",
|
||||||
|
Loading…
Reference in New Issue
Block a user