The great modularization.
Use ES6 module syntax and SystemJS modules for everything. Some testing stubs were added as well.
This commit is contained in:
parent
dd19e0ecbe
commit
473503a246
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.zip
|
||||||
|
*.xpi
|
4
extension/.gitignore
vendored
4
extension/.gitignore
vendored
@ -1,3 +1,7 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
*.js.map
|
*.js.map
|
||||||
background/*.js
|
background/*.js
|
||||||
|
lib/wallet/*.js
|
||||||
|
lib/*.js
|
||||||
|
popup/*.js
|
||||||
|
test/tests/*.js
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>
|
|
||||||
*/
|
|
||||||
"use strict";
|
|
||||||
const DB_NAME = "taler";
|
|
||||||
const DB_VERSION = 1;
|
|
||||||
/**
|
|
||||||
* Return a promise that resolves
|
|
||||||
* to the taler wallet db.
|
|
||||||
*/
|
|
||||||
function openTalerDb() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let req = indexedDB.open(DB_NAME, DB_VERSION);
|
|
||||||
req.onerror = (e) => {
|
|
||||||
reject(e);
|
|
||||||
};
|
|
||||||
req.onsuccess = (e) => {
|
|
||||||
resolve(req.result);
|
|
||||||
};
|
|
||||||
req.onupgradeneeded = (e) => {
|
|
||||||
let db = req.result;
|
|
||||||
console.log("DB: upgrade needed: oldVersion = " + e.oldVersion);
|
|
||||||
switch (e.oldVersion) {
|
|
||||||
case 0:
|
|
||||||
let mints = db.createObjectStore("mints", { keyPath: "baseUrl" });
|
|
||||||
mints.createIndex("pubKey", "keys.master_public_key");
|
|
||||||
db.createObjectStore("reserves", { keyPath: "reserve_pub" });
|
|
||||||
db.createObjectStore("denoms", { keyPath: "denomPub" });
|
|
||||||
let coins = db.createObjectStore("coins", { keyPath: "coinPub" });
|
|
||||||
coins.createIndex("mintBaseUrl", "mintBaseUrl");
|
|
||||||
db.createObjectStore("transactions", { keyPath: "contractHash" });
|
|
||||||
db.createObjectStore("precoins", { keyPath: "coinPub", autoIncrement: true });
|
|
||||||
db.createObjectStore("history", { keyPath: "id", autoIncrement: true });
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function exportDb(db) {
|
|
||||||
let dump = {
|
|
||||||
name: db.name,
|
|
||||||
version: db.version,
|
|
||||||
stores: {}
|
|
||||||
};
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let tx = db.transaction(db.objectStoreNames);
|
|
||||||
tx.addEventListener("complete", (e) => {
|
|
||||||
resolve(dump);
|
|
||||||
});
|
|
||||||
for (let i = 0; i < db.objectStoreNames.length; i++) {
|
|
||||||
let name = db.objectStoreNames[i];
|
|
||||||
let storeDump = {};
|
|
||||||
dump.stores[name] = storeDump;
|
|
||||||
let store = tx.objectStore(name)
|
|
||||||
.openCursor()
|
|
||||||
.addEventListener("success", (e) => {
|
|
||||||
let cursor = e.target.result;
|
|
||||||
if (cursor) {
|
|
||||||
storeDump[cursor.key] = cursor.value;
|
|
||||||
cursor.continue();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,643 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* High-level interface to emscripten-compiled modules used
|
|
||||||
* by the wallet.
|
|
||||||
* @module EmscriptIf
|
|
||||||
* @author Florian Dold
|
|
||||||
*/
|
|
||||||
"use strict";
|
|
||||||
// Size of a native pointer.
|
|
||||||
const PTR_SIZE = 4;
|
|
||||||
const GNUNET_OK = 1;
|
|
||||||
const GNUNET_YES = 1;
|
|
||||||
const GNUNET_NO = 0;
|
|
||||||
const GNUNET_SYSERR = -1;
|
|
||||||
let getEmsc = (...args) => Module.cwrap.apply(null, args);
|
|
||||||
var emsc = {
|
|
||||||
free: (ptr) => Module._free(ptr),
|
|
||||||
get_value: getEmsc('TALER_WR_get_value', 'number', ['number']),
|
|
||||||
get_fraction: getEmsc('TALER_WR_get_fraction', 'number', ['number']),
|
|
||||||
get_currency: getEmsc('TALER_WR_get_currency', 'string', ['number']),
|
|
||||||
amount_add: getEmsc('TALER_amount_add', 'number', ['number', 'number', 'number']),
|
|
||||||
amount_subtract: getEmsc('TALER_amount_subtract', 'number', ['number', 'number', 'number']),
|
|
||||||
amount_normalize: getEmsc('TALER_amount_normalize', 'void', ['number']),
|
|
||||||
amount_get_zero: getEmsc('TALER_amount_get_zero', 'number', ['string', 'number']),
|
|
||||||
amount_cmp: getEmsc('TALER_amount_cmp', 'number', ['number', 'number']),
|
|
||||||
amount_hton: getEmsc('TALER_amount_hton', 'void', ['number', 'number']),
|
|
||||||
amount_ntoh: getEmsc('TALER_amount_ntoh', 'void', ['number', 'number']),
|
|
||||||
hash: getEmsc('GNUNET_CRYPTO_hash', 'void', ['number', 'number', 'number']),
|
|
||||||
memmove: getEmsc('memmove', 'number', ['number', 'number', 'number']),
|
|
||||||
rsa_public_key_free: getEmsc('GNUNET_CRYPTO_rsa_public_key_free', 'void', ['number']),
|
|
||||||
rsa_signature_free: getEmsc('GNUNET_CRYPTO_rsa_signature_free', 'void', ['number']),
|
|
||||||
string_to_data: getEmsc('GNUNET_STRINGS_string_to_data', 'number', ['number', 'number', 'number', 'number']),
|
|
||||||
eddsa_sign: getEmsc('GNUNET_CRYPTO_eddsa_sign', 'number', ['number', 'number', 'number']),
|
|
||||||
hash_create_random: getEmsc('GNUNET_CRYPTO_hash_create_random', 'void', ['number', 'number']),
|
|
||||||
rsa_blinding_key_destroy: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_free', 'void', ['number']),
|
|
||||||
};
|
|
||||||
var emscAlloc = {
|
|
||||||
get_amount: getEmsc('TALER_WRALL_get_amount', 'number', ['number', 'number', 'number', 'string']),
|
|
||||||
eddsa_key_create: getEmsc('GNUNET_CRYPTO_eddsa_key_create', 'number', []),
|
|
||||||
eddsa_public_key_from_private: getEmsc('TALER_WRALL_eddsa_public_key_from_private', 'number', ['number']),
|
|
||||||
data_to_string_alloc: getEmsc('GNUNET_STRINGS_data_to_string_alloc', 'number', ['number', 'number']),
|
|
||||||
purpose_create: getEmsc('TALER_WRALL_purpose_create', 'number', ['number', 'number', 'number']),
|
|
||||||
rsa_blind: getEmsc('GNUNET_CRYPTO_rsa_blind', 'number', ['number', 'number', 'number', 'number']),
|
|
||||||
rsa_blinding_key_create: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_create', 'number', ['number']),
|
|
||||||
rsa_blinding_key_encode: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_encode', 'number', ['number', 'number']),
|
|
||||||
rsa_signature_encode: getEmsc('GNUNET_CRYPTO_rsa_signature_encode', 'number', ['number', 'number']),
|
|
||||||
rsa_blinding_key_decode: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_decode', 'number', ['number', 'number']),
|
|
||||||
rsa_public_key_decode: getEmsc('GNUNET_CRYPTO_rsa_public_key_decode', 'number', ['number', 'number']),
|
|
||||||
rsa_signature_decode: getEmsc('GNUNET_CRYPTO_rsa_signature_decode', 'number', ['number', 'number']),
|
|
||||||
rsa_public_key_encode: getEmsc('GNUNET_CRYPTO_rsa_public_key_encode', 'number', ['number', 'number']),
|
|
||||||
rsa_unblind: getEmsc('GNUNET_CRYPTO_rsa_unblind', 'number', ['number', 'number', 'number']),
|
|
||||||
malloc: (size) => Module._malloc(size),
|
|
||||||
};
|
|
||||||
var SignaturePurpose;
|
|
||||||
(function (SignaturePurpose) {
|
|
||||||
SignaturePurpose[SignaturePurpose["RESERVE_WITHDRAW"] = 1200] = "RESERVE_WITHDRAW";
|
|
||||||
SignaturePurpose[SignaturePurpose["WALLET_COIN_DEPOSIT"] = 1201] = "WALLET_COIN_DEPOSIT";
|
|
||||||
})(SignaturePurpose || (SignaturePurpose = {}));
|
|
||||||
var RandomQuality;
|
|
||||||
(function (RandomQuality) {
|
|
||||||
RandomQuality[RandomQuality["WEAK"] = 0] = "WEAK";
|
|
||||||
RandomQuality[RandomQuality["STRONG"] = 1] = "STRONG";
|
|
||||||
RandomQuality[RandomQuality["NONCE"] = 2] = "NONCE";
|
|
||||||
})(RandomQuality || (RandomQuality = {}));
|
|
||||||
class ArenaObject {
|
|
||||||
constructor(arena) {
|
|
||||||
this.nativePtr = null;
|
|
||||||
if (!arena) {
|
|
||||||
if (arenaStack.length == 0) {
|
|
||||||
throw Error("No arena available");
|
|
||||||
}
|
|
||||||
arena = arenaStack[arenaStack.length - 1];
|
|
||||||
}
|
|
||||||
arena.put(this);
|
|
||||||
this.arena = arena;
|
|
||||||
}
|
|
||||||
getNative() {
|
|
||||||
// We want to allow latent allocation
|
|
||||||
// of native wrappers, but we never want to
|
|
||||||
// pass 'undefined' to emscripten.
|
|
||||||
if (this._nativePtr === undefined) {
|
|
||||||
throw Error("Native pointer not initialized");
|
|
||||||
}
|
|
||||||
return this._nativePtr;
|
|
||||||
}
|
|
||||||
free() {
|
|
||||||
if (this.nativePtr !== undefined) {
|
|
||||||
emsc.free(this.nativePtr);
|
|
||||||
this.nativePtr = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
alloc(size) {
|
|
||||||
if (this.nativePtr !== undefined) {
|
|
||||||
throw Error("Double allocation");
|
|
||||||
}
|
|
||||||
this.nativePtr = emscAlloc.malloc(size);
|
|
||||||
}
|
|
||||||
setNative(n) {
|
|
||||||
if (n === undefined) {
|
|
||||||
throw Error("Native pointer must be a number or null");
|
|
||||||
}
|
|
||||||
this._nativePtr = n;
|
|
||||||
}
|
|
||||||
set nativePtr(v) {
|
|
||||||
this.setNative(v);
|
|
||||||
}
|
|
||||||
get nativePtr() {
|
|
||||||
return this.getNative();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class DefaultArena {
|
|
||||||
constructor() {
|
|
||||||
this.heap = [];
|
|
||||||
}
|
|
||||||
put(obj) {
|
|
||||||
this.heap.push(obj);
|
|
||||||
}
|
|
||||||
destroy() {
|
|
||||||
for (let obj of this.heap) {
|
|
||||||
obj.destroy();
|
|
||||||
}
|
|
||||||
this.heap = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Arena that destroys all its objects once control has returned to the message
|
|
||||||
* loop and a small interval has passed.
|
|
||||||
*/
|
|
||||||
class SyncArena extends DefaultArena {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
let me = this;
|
|
||||||
this.timer = new Worker('background/timerThread.js');
|
|
||||||
this.timer.onmessage = () => {
|
|
||||||
this.destroy();
|
|
||||||
};
|
|
||||||
//this.timer.postMessage({interval: 50});
|
|
||||||
}
|
|
||||||
destroy() {
|
|
||||||
super.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let arenaStack = [];
|
|
||||||
arenaStack.push(new SyncArena());
|
|
||||||
class Amount extends ArenaObject {
|
|
||||||
constructor(args, arena) {
|
|
||||||
super(arena);
|
|
||||||
if (args) {
|
|
||||||
this.nativePtr = emscAlloc.get_amount(args.value, 0, args.fraction, args.currency);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.nativePtr = emscAlloc.get_amount(0, 0, 0, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
destroy() {
|
|
||||||
if (this.nativePtr != 0) {
|
|
||||||
emsc.free(this.nativePtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static getZero(currency, a) {
|
|
||||||
let am = new Amount(null, a);
|
|
||||||
let r = emsc.amount_get_zero(currency, am.getNative());
|
|
||||||
if (r != GNUNET_OK) {
|
|
||||||
throw Error("invalid currency");
|
|
||||||
}
|
|
||||||
return am;
|
|
||||||
}
|
|
||||||
toNbo(a) {
|
|
||||||
let x = new AmountNbo(a);
|
|
||||||
x.alloc();
|
|
||||||
emsc.amount_hton(x.nativePtr, this.nativePtr);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
fromNbo(nbo) {
|
|
||||||
emsc.amount_ntoh(this.nativePtr, nbo.nativePtr);
|
|
||||||
}
|
|
||||||
get value() {
|
|
||||||
return emsc.get_value(this.nativePtr);
|
|
||||||
}
|
|
||||||
get fraction() {
|
|
||||||
return emsc.get_fraction(this.nativePtr);
|
|
||||||
}
|
|
||||||
get currency() {
|
|
||||||
return emsc.get_currency(this.nativePtr);
|
|
||||||
}
|
|
||||||
toJson() {
|
|
||||||
return {
|
|
||||||
value: emsc.get_value(this.nativePtr),
|
|
||||||
fraction: emsc.get_fraction(this.nativePtr),
|
|
||||||
currency: emsc.get_currency(this.nativePtr)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Add an amount to this amount.
|
|
||||||
*/
|
|
||||||
add(a) {
|
|
||||||
let res = emsc.amount_add(this.nativePtr, a.nativePtr, this.nativePtr);
|
|
||||||
if (res < 1) {
|
|
||||||
// Overflow
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Perform saturating subtraction on amounts.
|
|
||||||
*/
|
|
||||||
sub(a) {
|
|
||||||
// this = this - a
|
|
||||||
let res = emsc.amount_subtract(this.nativePtr, this.nativePtr, a.nativePtr);
|
|
||||||
if (res == 0) {
|
|
||||||
// Underflow
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (res > 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
throw Error("Incompatible currencies");
|
|
||||||
}
|
|
||||||
cmp(a) {
|
|
||||||
return emsc.amount_cmp(this.nativePtr, a.nativePtr);
|
|
||||||
}
|
|
||||||
normalize() {
|
|
||||||
emsc.amount_normalize(this.nativePtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class PackedArenaObject extends ArenaObject {
|
|
||||||
constructor(a) {
|
|
||||||
super(a);
|
|
||||||
}
|
|
||||||
toCrock() {
|
|
||||||
var d = emscAlloc.data_to_string_alloc(this.nativePtr, this.size());
|
|
||||||
var s = Module.Pointer_stringify(d);
|
|
||||||
emsc.free(d);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
toJson() {
|
|
||||||
// Per default, the json encoding of
|
|
||||||
// packed arena objects is just the crockford encoding.
|
|
||||||
// Subclasses typically want to override this.
|
|
||||||
return this.toCrock();
|
|
||||||
}
|
|
||||||
loadCrock(s) {
|
|
||||||
this.alloc();
|
|
||||||
// We need to get the javascript string
|
|
||||||
// to the emscripten heap first.
|
|
||||||
let buf = ByteArray.fromString(s);
|
|
||||||
let res = emsc.string_to_data(buf.nativePtr, s.length, this.nativePtr, this.size());
|
|
||||||
buf.destroy();
|
|
||||||
if (res < 1) {
|
|
||||||
throw { error: "wrong encoding" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
alloc() {
|
|
||||||
if (this.nativePtr === null) {
|
|
||||||
this.nativePtr = emscAlloc.malloc(this.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
destroy() {
|
|
||||||
emsc.free(this.nativePtr);
|
|
||||||
this.nativePtr = 0;
|
|
||||||
}
|
|
||||||
hash() {
|
|
||||||
var x = new HashCode();
|
|
||||||
x.alloc();
|
|
||||||
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() {
|
|
||||||
return 24;
|
|
||||||
}
|
|
||||||
toJson() {
|
|
||||||
let a = new DefaultArena();
|
|
||||||
let am = new Amount(null, a);
|
|
||||||
am.fromNbo(this);
|
|
||||||
let json = am.toJson();
|
|
||||||
a.destroy();
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class EddsaPrivateKey extends PackedArenaObject {
|
|
||||||
static create(a) {
|
|
||||||
let obj = new EddsaPrivateKey(a);
|
|
||||||
obj.nativePtr = emscAlloc.eddsa_key_create();
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
size() {
|
|
||||||
return 32;
|
|
||||||
}
|
|
||||||
getPublicKey(a) {
|
|
||||||
let obj = new EddsaPublicKey(a);
|
|
||||||
obj.nativePtr = emscAlloc.eddsa_public_key_from_private(this.nativePtr);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mixinStatic(EddsaPrivateKey, fromCrock);
|
|
||||||
function fromCrock(s) {
|
|
||||||
let x = new this();
|
|
||||||
x.alloc();
|
|
||||||
x.loadCrock(s);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
function mixin(obj, method, name) {
|
|
||||||
if (!name) {
|
|
||||||
name = method.name;
|
|
||||||
}
|
|
||||||
if (!name) {
|
|
||||||
throw Error("Mixin needs a name.");
|
|
||||||
}
|
|
||||||
obj.prototype[method.name] = method;
|
|
||||||
}
|
|
||||||
function mixinStatic(obj, method, name) {
|
|
||||||
if (!name) {
|
|
||||||
name = method.name;
|
|
||||||
}
|
|
||||||
if (!name) {
|
|
||||||
throw Error("Mixin needs a name.");
|
|
||||||
}
|
|
||||||
obj[method.name] = method;
|
|
||||||
}
|
|
||||||
class EddsaPublicKey extends PackedArenaObject {
|
|
||||||
size() {
|
|
||||||
return 32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mixinStatic(EddsaPublicKey, fromCrock);
|
|
||||||
function makeFromCrock(decodeFn) {
|
|
||||||
function fromCrock(s, a) {
|
|
||||||
let obj = new this(a);
|
|
||||||
let buf = ByteArray.fromCrock(s);
|
|
||||||
obj.setNative(decodeFn(buf.getNative(), buf.size()));
|
|
||||||
buf.destroy();
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
return fromCrock;
|
|
||||||
}
|
|
||||||
function makeToCrock(encodeFn) {
|
|
||||||
function toCrock() {
|
|
||||||
let ptr = emscAlloc.malloc(PTR_SIZE);
|
|
||||||
let size = emscAlloc.rsa_blinding_key_encode(this.nativePtr, ptr);
|
|
||||||
let res = new ByteArray(size, Module.getValue(ptr, '*'));
|
|
||||||
let s = res.toCrock();
|
|
||||||
emsc.free(ptr);
|
|
||||||
res.destroy();
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
return toCrock;
|
|
||||||
}
|
|
||||||
class RsaBlindingKey extends ArenaObject {
|
|
||||||
constructor(...args) {
|
|
||||||
super(...args);
|
|
||||||
this.toCrock = makeToCrock(emscAlloc.rsa_blinding_key_encode);
|
|
||||||
}
|
|
||||||
static create(len, a) {
|
|
||||||
let o = new RsaBlindingKey(a);
|
|
||||||
o.nativePtr = emscAlloc.rsa_blinding_key_create(len);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
destroy() {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mixinStatic(RsaBlindingKey, makeFromCrock(emscAlloc.rsa_blinding_key_decode));
|
|
||||||
class HashCode extends PackedArenaObject {
|
|
||||||
size() {
|
|
||||||
return 64;
|
|
||||||
}
|
|
||||||
random(qualStr) {
|
|
||||||
let qual;
|
|
||||||
switch (qualStr) {
|
|
||||||
case "weak":
|
|
||||||
qual = RandomQuality.WEAK;
|
|
||||||
break;
|
|
||||||
case "strong":
|
|
||||||
case null:
|
|
||||||
case undefined:
|
|
||||||
qual = RandomQuality.STRONG;
|
|
||||||
break;
|
|
||||||
case "nonce":
|
|
||||||
qual = RandomQuality.NONCE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw Error(format("unknown crypto quality: {0}", qual));
|
|
||||||
}
|
|
||||||
this.alloc();
|
|
||||||
emsc.hash_create_random(qual, this.nativePtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mixinStatic(HashCode, fromCrock);
|
|
||||||
class ByteArray extends PackedArenaObject {
|
|
||||||
constructor(desiredSize, init, a) {
|
|
||||||
super(a);
|
|
||||||
if (init === undefined || init === null) {
|
|
||||||
this.nativePtr = emscAlloc.malloc(desiredSize);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.nativePtr = init;
|
|
||||||
}
|
|
||||||
this.allocatedSize = desiredSize;
|
|
||||||
}
|
|
||||||
size() {
|
|
||||||
return this.allocatedSize;
|
|
||||||
}
|
|
||||||
static fromString(s, a) {
|
|
||||||
let hstr = emscAlloc.malloc(s.length + 1);
|
|
||||||
Module.writeStringToMemory(s, hstr);
|
|
||||||
return new ByteArray(s.length, hstr, a);
|
|
||||||
}
|
|
||||||
static fromCrock(s, a) {
|
|
||||||
let hstr = emscAlloc.malloc(s.length + 1);
|
|
||||||
Module.writeStringToMemory(s, hstr);
|
|
||||||
let decodedLen = Math.floor((s.length * 5) / 8);
|
|
||||||
let ba = new ByteArray(decodedLen, null, a);
|
|
||||||
let res = emsc.string_to_data(hstr, s.length, ba.nativePtr, decodedLen);
|
|
||||||
emsc.free(hstr);
|
|
||||||
if (res != GNUNET_OK) {
|
|
||||||
throw Error("decoding failed");
|
|
||||||
}
|
|
||||||
return ba;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class EccSignaturePurpose extends PackedArenaObject {
|
|
||||||
constructor(purpose, payload, a) {
|
|
||||||
super(a);
|
|
||||||
this.nativePtr = emscAlloc.purpose_create(purpose, payload.nativePtr, payload.size());
|
|
||||||
this.payloadSize = payload.size();
|
|
||||||
}
|
|
||||||
size() {
|
|
||||||
return this.payloadSize + 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class SignatureStruct {
|
|
||||||
constructor(x) {
|
|
||||||
this.members = {};
|
|
||||||
for (let k in x) {
|
|
||||||
this.set(k, x[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
toPurpose(a) {
|
|
||||||
let totalSize = 0;
|
|
||||||
for (let f of this.fieldTypes()) {
|
|
||||||
let name = f[0];
|
|
||||||
let member = this.members[name];
|
|
||||||
if (!member) {
|
|
||||||
throw Error(format("Member {0} not set", name));
|
|
||||||
}
|
|
||||||
totalSize += member.size();
|
|
||||||
}
|
|
||||||
let buf = emscAlloc.malloc(totalSize);
|
|
||||||
let ptr = buf;
|
|
||||||
for (let f of this.fieldTypes()) {
|
|
||||||
let name = f[0];
|
|
||||||
let member = this.members[name];
|
|
||||||
let size = member.size();
|
|
||||||
emsc.memmove(ptr, member.nativePtr, size);
|
|
||||||
ptr += size;
|
|
||||||
}
|
|
||||||
let ba = new ByteArray(totalSize, buf, a);
|
|
||||||
return new EccSignaturePurpose(this.purpose(), ba);
|
|
||||||
}
|
|
||||||
toJson() {
|
|
||||||
let res = {};
|
|
||||||
for (let f of this.fieldTypes()) {
|
|
||||||
let name = f[0];
|
|
||||||
let member = this.members[name];
|
|
||||||
if (!member) {
|
|
||||||
throw Error(format("Member {0} not set", name));
|
|
||||||
}
|
|
||||||
res[name] = member.toJson();
|
|
||||||
}
|
|
||||||
res["purpose"] = this.purpose();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
set(name, value) {
|
|
||||||
let typemap = {};
|
|
||||||
for (let f of this.fieldTypes()) {
|
|
||||||
typemap[f[0]] = f[1];
|
|
||||||
}
|
|
||||||
if (!(name in typemap)) {
|
|
||||||
throw Error(format("Key {0} not found", name));
|
|
||||||
}
|
|
||||||
if (!(value instanceof typemap[name])) {
|
|
||||||
throw Error(format("Wrong type for {0}", name));
|
|
||||||
}
|
|
||||||
this.members[name] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class WithdrawRequestPS extends SignatureStruct {
|
|
||||||
constructor(w) {
|
|
||||||
super(w);
|
|
||||||
}
|
|
||||||
purpose() {
|
|
||||||
return SignaturePurpose.RESERVE_WITHDRAW;
|
|
||||||
}
|
|
||||||
fieldTypes() {
|
|
||||||
return [
|
|
||||||
["reserve_pub", EddsaPublicKey],
|
|
||||||
["amount_with_fee", AmountNbo],
|
|
||||||
["withdraw_fee", AmountNbo],
|
|
||||||
["h_denomination_pub", HashCode],
|
|
||||||
["h_coin_envelope", HashCode]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class AbsoluteTimeNbo extends PackedArenaObject {
|
|
||||||
static fromTalerString(s) {
|
|
||||||
let x = new AbsoluteTimeNbo();
|
|
||||||
x.alloc();
|
|
||||||
let r = /Date\(([0-9]+)\)/;
|
|
||||||
let m = r.exec(s);
|
|
||||||
if (m.length != 2) {
|
|
||||||
throw Error();
|
|
||||||
}
|
|
||||||
let n = parseInt(m[1]) * 1000000;
|
|
||||||
// XXX: This only works up to 54 bit numbers.
|
|
||||||
set64(x.getNative(), n);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
size() {
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// XXX: This only works up to 54 bit numbers.
|
|
||||||
function set64(p, n) {
|
|
||||||
for (let i = 0; i < 8; ++i) {
|
|
||||||
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();
|
|
||||||
set64(x.getNative(), n);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
size() {
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class DepositRequestPS extends SignatureStruct {
|
|
||||||
constructor(w) {
|
|
||||||
super(w);
|
|
||||||
}
|
|
||||||
purpose() {
|
|
||||||
return SignaturePurpose.WALLET_COIN_DEPOSIT;
|
|
||||||
}
|
|
||||||
fieldTypes() {
|
|
||||||
return [
|
|
||||||
["h_contract", HashCode],
|
|
||||||
["h_wire", HashCode],
|
|
||||||
["timestamp", AbsoluteTimeNbo],
|
|
||||||
["refund_deadline", AbsoluteTimeNbo],
|
|
||||||
["transaction_id", UInt64],
|
|
||||||
["amount_with_fee", AmountNbo],
|
|
||||||
["deposit_fee", AmountNbo],
|
|
||||||
["merchant", EddsaPublicKey],
|
|
||||||
["coin_pub", EddsaPublicKey],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function makeEncode(encodeFn) {
|
|
||||||
function encode(arena) {
|
|
||||||
let ptr = emscAlloc.malloc(PTR_SIZE);
|
|
||||||
let len = encodeFn(this.getNative(), ptr);
|
|
||||||
let res = new ByteArray(len, null, arena);
|
|
||||||
res.setNative(Module.getValue(ptr, '*'));
|
|
||||||
emsc.free(ptr);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return encode;
|
|
||||||
}
|
|
||||||
class RsaPublicKey extends ArenaObject {
|
|
||||||
toCrock() {
|
|
||||||
return this.encode().toCrock();
|
|
||||||
}
|
|
||||||
destroy() {
|
|
||||||
emsc.rsa_public_key_free(this.nativePtr);
|
|
||||||
this.nativePtr = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mixinStatic(RsaPublicKey, makeFromCrock(emscAlloc.rsa_public_key_decode));
|
|
||||||
mixin(RsaPublicKey, makeEncode(emscAlloc.rsa_public_key_encode));
|
|
||||||
class EddsaSignature extends PackedArenaObject {
|
|
||||||
size() {
|
|
||||||
return 64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class RsaSignature extends ArenaObject {
|
|
||||||
destroy() {
|
|
||||||
emsc.rsa_signature_free(this.getNative());
|
|
||||||
this.setNative(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mixinStatic(RsaSignature, makeFromCrock(emscAlloc.rsa_signature_decode));
|
|
||||||
mixin(RsaSignature, makeEncode(emscAlloc.rsa_signature_encode));
|
|
||||||
function rsaBlind(hashCode, blindingKey, pkey, arena) {
|
|
||||||
let ptr = emscAlloc.malloc(PTR_SIZE);
|
|
||||||
let s = emscAlloc.rsa_blind(hashCode.nativePtr, blindingKey.nativePtr, pkey.nativePtr, ptr);
|
|
||||||
return new ByteArray(s, Module.getValue(ptr, '*'), arena);
|
|
||||||
}
|
|
||||||
function eddsaSign(purpose, priv, a) {
|
|
||||||
let sig = new EddsaSignature(a);
|
|
||||||
sig.alloc();
|
|
||||||
let res = emsc.eddsa_sign(priv.nativePtr, purpose.nativePtr, sig.nativePtr);
|
|
||||||
if (res < 1) {
|
|
||||||
throw Error("EdDSA signing failed");
|
|
||||||
}
|
|
||||||
return sig;
|
|
||||||
}
|
|
||||||
function rsaUnblind(sig, bk, pk, a) {
|
|
||||||
let x = new RsaSignature(a);
|
|
||||||
x.nativePtr = emscAlloc.rsa_unblind(sig.nativePtr, bk.nativePtr, pk.nativePtr);
|
|
||||||
return x;
|
|
||||||
}
|
|
42
extension/background/main.ts
Normal file
42
extension/background/main.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
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/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Entry point for the background page.
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
System.config({
|
||||||
|
defaultJSExtensions: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
var Module: any;
|
||||||
|
|
||||||
|
if ("object" !== typeof Module) {
|
||||||
|
throw Error("emscripten not loaded, no 'Module' defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mod = System.newModule({Module: Module});
|
||||||
|
let modName = System.normalizeSync("../lib/emscripten/emsc");
|
||||||
|
console.log("registering", modName);
|
||||||
|
System.set(modName, mod);
|
||||||
|
|
||||||
|
System.import("../lib/wallet/wxmessaging")
|
||||||
|
.then((wxmessaging) => {
|
||||||
|
wxmessaging.wxMain();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error("import failed", e.stack);
|
||||||
|
});
|
@ -1,502 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* High-level wallet operations that should be indepentent from the underlying
|
|
||||||
* browser extension interface.
|
|
||||||
* @module Wallet
|
|
||||||
* @author Florian Dold
|
|
||||||
*/
|
|
||||||
/// <reference path="../decl/urijs/URIjs.d.ts" />
|
|
||||||
"use strict";
|
|
||||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
||||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
||||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
||||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
||||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
||||||
};
|
|
||||||
let AmountJson = class {
|
|
||||||
};
|
|
||||||
__decorate([
|
|
||||||
Checkable.Number
|
|
||||||
], AmountJson.prototype, "value", void 0);
|
|
||||||
__decorate([
|
|
||||||
Checkable.Number
|
|
||||||
], AmountJson.prototype, "fraction", void 0);
|
|
||||||
__decorate([
|
|
||||||
Checkable.String
|
|
||||||
], AmountJson.prototype, "currency", void 0);
|
|
||||||
AmountJson = __decorate([
|
|
||||||
Checkable.Class
|
|
||||||
], AmountJson);
|
|
||||||
let CoinPaySig = class {
|
|
||||||
};
|
|
||||||
__decorate([
|
|
||||||
Checkable.String
|
|
||||||
], CoinPaySig.prototype, "coin_sig", void 0);
|
|
||||||
__decorate([
|
|
||||||
Checkable.String
|
|
||||||
], CoinPaySig.prototype, "coin_pub", void 0);
|
|
||||||
__decorate([
|
|
||||||
Checkable.String
|
|
||||||
], CoinPaySig.prototype, "ub_sig", void 0);
|
|
||||||
__decorate([
|
|
||||||
Checkable.String
|
|
||||||
], CoinPaySig.prototype, "denom_pub", void 0);
|
|
||||||
__decorate([
|
|
||||||
Checkable.Value(AmountJson)
|
|
||||||
], CoinPaySig.prototype, "f", void 0);
|
|
||||||
CoinPaySig = __decorate([
|
|
||||||
Checkable.Class
|
|
||||||
], CoinPaySig);
|
|
||||||
/**
|
|
||||||
* 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 copy(o) {
|
|
||||||
return JSON.parse(JSON.stringify(o));
|
|
||||||
}
|
|
||||||
function rankDenom(denom1, denom2) {
|
|
||||||
// Slow ... we should find a better way than to convert it evert time.
|
|
||||||
let v1 = new Amount(denom1.value);
|
|
||||||
let v2 = new Amount(denom2.value);
|
|
||||||
return (-1) * v1.cmp(v2);
|
|
||||||
}
|
|
||||||
class Wallet {
|
|
||||||
constructor(db, http, badge) {
|
|
||||||
this.db = db;
|
|
||||||
this.http = http;
|
|
||||||
this.badge = badge;
|
|
||||||
}
|
|
||||||
static signDeposit(offer, cds) {
|
|
||||||
let ret = [];
|
|
||||||
let amountSpent = Amount.getZero(cds[0].coin.currentAmount.currency);
|
|
||||||
let amountRemaining = new Amount(offer.contract.amount);
|
|
||||||
cds = copy(cds);
|
|
||||||
for (let cd of cds) {
|
|
||||||
let coinSpend;
|
|
||||||
if (amountRemaining.value == 0 && amountRemaining.fraction == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (amountRemaining.cmp(new Amount(cd.coin.currentAmount)) < 0) {
|
|
||||||
coinSpend = new Amount(amountRemaining.toJson());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
coinSpend = new Amount(cd.coin.currentAmount);
|
|
||||||
}
|
|
||||||
amountSpent.add(coinSpend);
|
|
||||||
amountRemaining.sub(coinSpend);
|
|
||||||
let newAmount = new Amount(cd.coin.currentAmount);
|
|
||||||
newAmount.sub(coinSpend);
|
|
||||||
cd.coin.currentAmount = newAmount.toJson();
|
|
||||||
let args = {
|
|
||||||
h_contract: HashCode.fromCrock(offer.H_contract),
|
|
||||||
h_wire: HashCode.fromCrock(offer.contract.H_wire),
|
|
||||||
amount_with_fee: coinSpend.toNbo(),
|
|
||||||
coin_pub: EddsaPublicKey.fromCrock(cd.coin.coinPub),
|
|
||||||
deposit_fee: new Amount(cd.denom.fee_deposit).toNbo(),
|
|
||||||
merchant: EddsaPublicKey.fromCrock(offer.contract.merchant_pub),
|
|
||||||
refund_deadline: AbsoluteTimeNbo.fromTalerString(offer.contract.refund_deadline),
|
|
||||||
timestamp: AbsoluteTimeNbo.fromTalerString(offer.contract.timestamp),
|
|
||||||
transaction_id: UInt64.fromNumber(offer.contract.transaction_id),
|
|
||||||
};
|
|
||||||
let d = new DepositRequestPS(args);
|
|
||||||
let coinSig = eddsaSign(d.toPurpose(), EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
|
|
||||||
.toCrock();
|
|
||||||
let s = {
|
|
||||||
coin_sig: coinSig,
|
|
||||||
coin_pub: cd.coin.coinPub,
|
|
||||||
ub_sig: cd.coin.denomSig,
|
|
||||||
denom_pub: cd.coin.denomPub,
|
|
||||||
f: coinSpend.toJson(),
|
|
||||||
};
|
|
||||||
ret.push({ sig: s, updatedCoin: cd.coin });
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Get mints and associated coins that are still spendable,
|
|
||||||
* but only if the sum the coins' remaining value exceeds the payment amount.
|
|
||||||
* @param paymentAmount
|
|
||||||
* @param depositFeeLimit
|
|
||||||
* @param allowedMints
|
|
||||||
*/
|
|
||||||
getPossibleMintCoins(paymentAmount, depositFeeLimit, allowedMints) {
|
|
||||||
let m = {};
|
|
||||||
function storeMintCoin(mc) {
|
|
||||||
let mint = mc[0];
|
|
||||||
let coin = mc[1];
|
|
||||||
let cd = {
|
|
||||||
coin: coin,
|
|
||||||
denom: mint.keys.denoms.find((e) => e.denom_pub === coin.denomPub)
|
|
||||||
};
|
|
||||||
if (!cd.denom) {
|
|
||||||
throw Error("denom not found (database inconsistent)");
|
|
||||||
}
|
|
||||||
let x = m[mint.baseUrl];
|
|
||||||
if (!x) {
|
|
||||||
m[mint.baseUrl] = [cd];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
x.push(cd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let ps = allowedMints.map((info) => {
|
|
||||||
return Query(this.db)
|
|
||||||
.iterIndex("mints", "pubKey", info.master_pub)
|
|
||||||
.indexJoin("coins", "mintBaseUrl", (mint) => mint.baseUrl)
|
|
||||||
.reduce(storeMintCoin);
|
|
||||||
});
|
|
||||||
return Promise.all(ps).then(() => {
|
|
||||||
let ret = {};
|
|
||||||
nextMint: for (let key in m) {
|
|
||||||
let coins = m[key].map((x) => ({
|
|
||||||
a: new Amount(x.denom.fee_deposit),
|
|
||||||
c: x
|
|
||||||
}));
|
|
||||||
// Sort by ascending deposit fee
|
|
||||||
coins.sort((o1, o2) => o1.a.cmp(o2.a));
|
|
||||||
let maxFee = new Amount(depositFeeLimit);
|
|
||||||
let minAmount = new Amount(paymentAmount);
|
|
||||||
let accFee = new Amount(coins[0].c.denom.fee_deposit);
|
|
||||||
let accAmount = Amount.getZero(coins[0].c.coin.currentAmount.currency);
|
|
||||||
let usableCoins = [];
|
|
||||||
nextCoin: for (let i = 0; i < coins.length; i++) {
|
|
||||||
let coinAmount = new Amount(coins[i].c.coin.currentAmount);
|
|
||||||
let coinFee = coins[i].a;
|
|
||||||
if (coinAmount.cmp(coinFee) <= 0) {
|
|
||||||
continue nextCoin;
|
|
||||||
}
|
|
||||||
accFee.add(coinFee);
|
|
||||||
accAmount.add(coinAmount);
|
|
||||||
if (accFee.cmp(maxFee) >= 0) {
|
|
||||||
console.log("too much fees");
|
|
||||||
continue nextMint;
|
|
||||||
}
|
|
||||||
usableCoins.push(coins[i].c);
|
|
||||||
if (accAmount.cmp(minAmount) >= 0) {
|
|
||||||
ret[key] = usableCoins;
|
|
||||||
continue nextMint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
executePay(offer, payCoinInfo, merchantBaseUrl, chosenMint) {
|
|
||||||
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
|
|
||||||
};
|
|
||||||
return Query(this.db)
|
|
||||||
.put("transactions", t)
|
|
||||||
.putAll("coins", payCoinInfo.map((pci) => pci.updatedCoin))
|
|
||||||
.finish();
|
|
||||||
}
|
|
||||||
confirmPay(offer, merchantPageUrl) {
|
|
||||||
return Promise.resolve().then(() => {
|
|
||||||
return this.getPossibleMintCoins(offer.contract.amount, offer.contract.max_fee, offer.contract.mints);
|
|
||||||
}).then((mcs) => {
|
|
||||||
if (Object.keys(mcs).length == 0) {
|
|
||||||
throw Error("Not enough coins.");
|
|
||||||
}
|
|
||||||
let mintUrl = Object.keys(mcs)[0];
|
|
||||||
let ds = Wallet.signDeposit(offer, mcs[mintUrl]);
|
|
||||||
return this.executePay(offer, ds, merchantPageUrl, mintUrl);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
doPayment(H_contract) {
|
|
||||||
return Promise.resolve().then(() => {
|
|
||||||
return Query(this.db)
|
|
||||||
.get("transactions", H_contract)
|
|
||||||
.then((t) => {
|
|
||||||
if (!t) {
|
|
||||||
throw Error("contract not found");
|
|
||||||
}
|
|
||||||
let resp = {
|
|
||||||
payUrl: t.payUrl,
|
|
||||||
payReq: t.payReq
|
|
||||||
};
|
|
||||||
return resp;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
confirmReserve(req) {
|
|
||||||
let reservePriv = EddsaPrivateKey.create();
|
|
||||||
let reservePub = reservePriv.getPublicKey();
|
|
||||||
let form = new FormData();
|
|
||||||
let now = (new Date()).toString();
|
|
||||||
form.append(req.field_amount, req.amount_str);
|
|
||||||
form.append(req.field_reserve_pub, reservePub.toCrock());
|
|
||||||
form.append(req.field_mint, req.mint);
|
|
||||||
// TODO: set bank-specified fields.
|
|
||||||
let mintBaseUrl = canonicalizeBaseUrl(req.mint);
|
|
||||||
return this.http.postForm(req.post_url, form)
|
|
||||||
.then((hresp) => {
|
|
||||||
let resp = {
|
|
||||||
status: hresp.status,
|
|
||||||
text: hresp.responseText,
|
|
||||||
success: undefined,
|
|
||||||
backlink: undefined
|
|
||||||
};
|
|
||||||
let reserveRecord = {
|
|
||||||
reserve_pub: reservePub.toCrock(),
|
|
||||||
reserve_priv: reservePriv.toCrock(),
|
|
||||||
mint_base_url: mintBaseUrl,
|
|
||||||
created: now,
|
|
||||||
last_query: null,
|
|
||||||
current_amount: null,
|
|
||||||
// XXX: set to actual amount
|
|
||||||
initial_amount: null
|
|
||||||
};
|
|
||||||
if (hresp.status != 200) {
|
|
||||||
resp.success = false;
|
|
||||||
return resp;
|
|
||||||
}
|
|
||||||
resp.success = true;
|
|
||||||
// We can't show the page directly, so
|
|
||||||
// we show some generic page from the wallet.
|
|
||||||
resp.backlink = null;
|
|
||||||
return Query(this.db)
|
|
||||||
.put("reserves", reserveRecord)
|
|
||||||
.finish()
|
|
||||||
.then(() => {
|
|
||||||
// Do this in the background
|
|
||||||
this.updateMintFromUrl(reserveRecord.mint_base_url)
|
|
||||||
.then((mint) => this.updateReserve(reservePub, mint)
|
|
||||||
.then((reserve) => this.depleteReserve(reserve, mint)));
|
|
||||||
return resp;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
withdrawPrepare(denom, reserve) {
|
|
||||||
let reservePriv = new EddsaPrivateKey();
|
|
||||||
reservePriv.loadCrock(reserve.reserve_priv);
|
|
||||||
let reservePub = new EddsaPublicKey();
|
|
||||||
reservePub.loadCrock(reserve.reserve_pub);
|
|
||||||
let denomPub = RsaPublicKey.fromCrock(denom.denom_pub);
|
|
||||||
let coinPriv = EddsaPrivateKey.create();
|
|
||||||
let coinPub = coinPriv.getPublicKey();
|
|
||||||
let blindingFactor = RsaBlindingKey.create(1024);
|
|
||||||
let pubHash = coinPub.hash();
|
|
||||||
let ev = rsaBlind(pubHash, blindingFactor, denomPub);
|
|
||||||
if (!denom.fee_withdraw) {
|
|
||||||
throw Error("Field fee_withdraw missing");
|
|
||||||
}
|
|
||||||
let amountWithFee = new Amount(denom.value);
|
|
||||||
amountWithFee.add(new Amount(denom.fee_withdraw));
|
|
||||||
let withdrawFee = new Amount(denom.fee_withdraw);
|
|
||||||
// Signature
|
|
||||||
let withdrawRequest = new WithdrawRequestPS({
|
|
||||||
reserve_pub: reservePub,
|
|
||||||
amount_with_fee: amountWithFee.toNbo(),
|
|
||||||
withdraw_fee: withdrawFee.toNbo(),
|
|
||||||
h_denomination_pub: denomPub.encode().hash(),
|
|
||||||
h_coin_envelope: ev.hash()
|
|
||||||
});
|
|
||||||
var sig = eddsaSign(withdrawRequest.toPurpose(), reservePriv);
|
|
||||||
let preCoin = {
|
|
||||||
reservePub: reservePub.toCrock(),
|
|
||||||
blindingKey: blindingFactor.toCrock(),
|
|
||||||
coinPub: coinPub.toCrock(),
|
|
||||||
coinPriv: coinPriv.toCrock(),
|
|
||||||
denomPub: denomPub.encode().toCrock(),
|
|
||||||
mintBaseUrl: reserve.mint_base_url,
|
|
||||||
withdrawSig: sig.toCrock(),
|
|
||||||
coinEv: ev.toCrock(),
|
|
||||||
coinValue: denom.value
|
|
||||||
};
|
|
||||||
return Query(this.db).put("precoins", preCoin).finish().then(() => preCoin);
|
|
||||||
}
|
|
||||||
withdrawExecute(pc) {
|
|
||||||
return Query(this.db)
|
|
||||||
.get("reserves", pc.reservePub)
|
|
||||||
.then((r) => {
|
|
||||||
let wd = {};
|
|
||||||
wd.denom_pub = pc.denomPub;
|
|
||||||
wd.reserve_pub = pc.reservePub;
|
|
||||||
wd.reserve_sig = pc.withdrawSig;
|
|
||||||
wd.coin_ev = pc.coinEv;
|
|
||||||
let reqUrl = URI("reserve/withdraw").absoluteTo(r.mint_base_url);
|
|
||||||
return this.http.postJson(reqUrl, wd);
|
|
||||||
})
|
|
||||||
.then(resp => {
|
|
||||||
if (resp.status != 200) {
|
|
||||||
throw new RequestException({
|
|
||||||
hint: "Withdrawal failed",
|
|
||||||
status: resp.status
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let r = JSON.parse(resp.responseText);
|
|
||||||
let denomSig = rsaUnblind(RsaSignature.fromCrock(r.ev_sig), RsaBlindingKey.fromCrock(pc.blindingKey), RsaPublicKey.fromCrock(pc.denomPub));
|
|
||||||
let coin = {
|
|
||||||
coinPub: pc.coinPub,
|
|
||||||
coinPriv: pc.coinPriv,
|
|
||||||
denomPub: pc.denomPub,
|
|
||||||
denomSig: denomSig.encode().toCrock(),
|
|
||||||
currentAmount: pc.coinValue,
|
|
||||||
mintBaseUrl: pc.mintBaseUrl,
|
|
||||||
};
|
|
||||||
return coin;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
updateBadge() {
|
|
||||||
function countNonEmpty(c, n) {
|
|
||||||
if (c.currentAmount.fraction != 0 || c.currentAmount.value != 0) {
|
|
||||||
return n + 1;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
function doBadge(n) {
|
|
||||||
this.badge.setText(n.toString());
|
|
||||||
this.badge.setColor("#0F0");
|
|
||||||
}
|
|
||||||
Query(this.db)
|
|
||||||
.iter("coins")
|
|
||||||
.reduce(countNonEmpty, 0)
|
|
||||||
.then(doBadge.bind(this));
|
|
||||||
}
|
|
||||||
storeCoin(coin) {
|
|
||||||
Query(this.db)
|
|
||||||
.delete("precoins", coin.coinPub)
|
|
||||||
.add("coins", coin)
|
|
||||||
.finish()
|
|
||||||
.then(() => {
|
|
||||||
this.updateBadge();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
withdraw(denom, reserve) {
|
|
||||||
return this.withdrawPrepare(denom, reserve)
|
|
||||||
.then((pc) => this.withdrawExecute(pc))
|
|
||||||
.then((c) => this.storeCoin(c));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Withdraw coins from a reserve until it is empty.
|
|
||||||
*/
|
|
||||||
depleteReserve(reserve, mint) {
|
|
||||||
let denoms = copy(mint.keys.denoms);
|
|
||||||
let remaining = new Amount(reserve.current_amount);
|
|
||||||
denoms.sort(rankDenom);
|
|
||||||
let workList = [];
|
|
||||||
for (let i = 0; i < 1000; i++) {
|
|
||||||
let found = false;
|
|
||||||
for (let d of denoms) {
|
|
||||||
let cost = new Amount(d.value);
|
|
||||||
cost.add(new Amount(d.fee_withdraw));
|
|
||||||
if (remaining.cmp(cost) < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
found = true;
|
|
||||||
remaining.sub(cost);
|
|
||||||
workList.push(d);
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
console.log("did not find coins for remaining ", remaining.toJson());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Do the request one by one.
|
|
||||||
let next = () => {
|
|
||||||
if (workList.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let d = workList.pop();
|
|
||||||
this.withdraw(d, reserve)
|
|
||||||
.then(() => next());
|
|
||||||
};
|
|
||||||
// Asynchronous recursion
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
updateReserve(reservePub, mint) {
|
|
||||||
let reservePubStr = reservePub.toCrock();
|
|
||||||
return Query(this.db)
|
|
||||||
.get("reserves", reservePubStr)
|
|
||||||
.then((reserve) => {
|
|
||||||
let reqUrl = URI("reserve/status").absoluteTo(mint.baseUrl);
|
|
||||||
reqUrl.query({ 'reserve_pub': reservePubStr });
|
|
||||||
return this.http.get(reqUrl).then(resp => {
|
|
||||||
if (resp.status != 200) {
|
|
||||||
throw Error();
|
|
||||||
}
|
|
||||||
let reserveInfo = JSON.parse(resp.responseText);
|
|
||||||
if (!reserveInfo) {
|
|
||||||
throw Error();
|
|
||||||
}
|
|
||||||
reserve.current_amount = reserveInfo.balance;
|
|
||||||
return Query(this.db)
|
|
||||||
.put("reserves", reserve)
|
|
||||||
.finish()
|
|
||||||
.then(() => reserve);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Update or add mint DB entry by fetching the /keys information.
|
|
||||||
* Optionally link the reserve entry to the new or existing
|
|
||||||
* mint entry in then DB.
|
|
||||||
*/
|
|
||||||
updateMintFromUrl(baseUrl) {
|
|
||||||
let reqUrl = URI("keys").absoluteTo(baseUrl);
|
|
||||||
return this.http.get(reqUrl).then((resp) => {
|
|
||||||
if (resp.status != 200) {
|
|
||||||
throw Error("/keys request failed");
|
|
||||||
}
|
|
||||||
let mintKeysJson = JSON.parse(resp.responseText);
|
|
||||||
if (!mintKeysJson) {
|
|
||||||
throw new RequestException({ url: reqUrl, hint: "keys invalid" });
|
|
||||||
}
|
|
||||||
let mint = {
|
|
||||||
baseUrl: baseUrl,
|
|
||||||
keys: mintKeysJson
|
|
||||||
};
|
|
||||||
return Query(this.db).put("mints", mint).finish().then(() => mint);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getBalances() {
|
|
||||||
function collectBalances(c, byCurrency) {
|
|
||||||
let acc = byCurrency[c.currentAmount.currency];
|
|
||||||
if (!acc) {
|
|
||||||
acc = Amount.getZero(c.currentAmount.currency).toJson();
|
|
||||||
}
|
|
||||||
let am = new Amount(c.currentAmount);
|
|
||||||
am.add(new Amount(acc));
|
|
||||||
byCurrency[c.currentAmount.currency] = am.toJson();
|
|
||||||
return byCurrency;
|
|
||||||
}
|
|
||||||
return Query(this.db)
|
|
||||||
.iter("coins")
|
|
||||||
.reduce(collectBalances, {});
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,29 +15,30 @@
|
|||||||
*/
|
*/
|
||||||
// Script that is injected into pages in order to allow merchants pages to
|
// Script that is injected into pages in order to allow merchants pages to
|
||||||
// query the availability of Taler.
|
// query the availability of Taler.
|
||||||
|
/// <reference path="../lib/decl/chrome/chrome.d.ts" />
|
||||||
"use strict";
|
"use strict";
|
||||||
document.addEventListener("taler-checkout-probe", function (e) {
|
document.addEventListener("taler-checkout-probe", function (e) {
|
||||||
let evt = new Event("taler-wallet-present");
|
var evt = new Event("taler-wallet-present");
|
||||||
document.dispatchEvent(evt);
|
document.dispatchEvent(evt);
|
||||||
console.log("merchant handshake done");
|
console.log("merchant handshake done");
|
||||||
});
|
});
|
||||||
document.addEventListener("taler-wire-probe", function (e) {
|
document.addEventListener("taler-wire-probe", function (e) {
|
||||||
let evt = new Event("taler-wallet-present");
|
var evt = new Event("taler-wallet-present");
|
||||||
document.dispatchEvent(evt);
|
document.dispatchEvent(evt);
|
||||||
console.log("bank handshake done");
|
console.log("bank handshake done");
|
||||||
});
|
});
|
||||||
document.addEventListener("taler-checkout-probe", function (e) {
|
document.addEventListener("taler-checkout-probe", function (e) {
|
||||||
let evt = new Event("taler-wallet-present");
|
var evt = new Event("taler-wallet-present");
|
||||||
document.dispatchEvent(evt);
|
document.dispatchEvent(evt);
|
||||||
console.log("merchant handshake done");
|
console.log("merchant handshake done");
|
||||||
});
|
});
|
||||||
document.addEventListener("taler-create-reserve", function (e) {
|
document.addEventListener("taler-create-reserve", function (e) {
|
||||||
let $ = (x) => document.getElementById(x);
|
var $ = function (x) { return document.getElementById(x); };
|
||||||
console.log("taler-create-reserve with " + JSON.stringify(e.detail));
|
console.log("taler-create-reserve with " + JSON.stringify(e.detail));
|
||||||
let form_uri = $(e.detail.form_id).action;
|
var form_uri = $(e.detail.form_id).action;
|
||||||
// TODO: validate event fields
|
// TODO: validate event fields
|
||||||
// TODO: also send extra bank-defined form fields
|
// TODO: also send extra bank-defined form fields
|
||||||
let params = {
|
var params = {
|
||||||
post_url: URI(form_uri).absoluteTo(document.location.href).href(),
|
post_url: URI(form_uri).absoluteTo(document.location.href).href(),
|
||||||
// TODO: This should change in the future, we should not deal with the
|
// TODO: This should change in the future, we should not deal with the
|
||||||
// amount as a bank-specific string here.
|
// amount as a bank-specific string here.
|
||||||
@ -47,14 +48,14 @@ document.addEventListener("taler-create-reserve", function (e) {
|
|||||||
field_reserve_pub: $(e.detail.input_pub).name,
|
field_reserve_pub: $(e.detail.input_pub).name,
|
||||||
field_mint: $(e.detail.mint_rcv).name,
|
field_mint: $(e.detail.mint_rcv).name,
|
||||||
};
|
};
|
||||||
let uri = URI(chrome.extension.getURL("pages/confirm-create-reserve.html"));
|
var uri = URI(chrome.extension.getURL("pages/confirm-create-reserve.html"));
|
||||||
document.location.href = uri.query(params).href();
|
document.location.href = uri.query(params).href();
|
||||||
});
|
});
|
||||||
document.addEventListener("taler-contract", function (e) {
|
document.addEventListener("taler-contract", function (e) {
|
||||||
// XXX: the merchant should just give us the parsed data ...
|
// XXX: the merchant should just give us the parsed data ...
|
||||||
let offer = JSON.parse(e.detail);
|
var offer = JSON.parse(e.detail);
|
||||||
let uri = URI(chrome.extension.getURL("pages/confirm-contract.html"));
|
var uri = URI(chrome.extension.getURL("pages/confirm-contract.html"));
|
||||||
let params = {
|
var params = {
|
||||||
offer: JSON.stringify(offer),
|
offer: JSON.stringify(offer),
|
||||||
merchantPageUrl: document.location.href,
|
merchantPageUrl: document.location.href,
|
||||||
cookie: document.cookie,
|
cookie: document.cookie,
|
||||||
@ -63,23 +64,23 @@ 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");
|
||||||
let 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, (resp) => {
|
chrome.runtime.sendMessage(msg, function (resp) {
|
||||||
if (!resp.success) {
|
if (!resp.success) {
|
||||||
console.log("failure!");
|
console.log("failure!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("Making request to ", resp.payUrl);
|
console.log("Making request to ", resp.payUrl);
|
||||||
let r = new XMLHttpRequest();
|
var r = new XMLHttpRequest();
|
||||||
r.open('post', resp.payUrl);
|
r.open('post', resp.payUrl);
|
||||||
r.send(JSON.stringify(resp.payReq));
|
r.send(JSON.stringify(resp.payReq));
|
||||||
let detail = {};
|
var detail = {};
|
||||||
r.onload = (e) => {
|
r.onload = function (e) {
|
||||||
switch (r.status) {
|
switch (r.status) {
|
||||||
case 200:
|
case 200:
|
||||||
detail.success = true;
|
detail.success = true;
|
||||||
@ -101,3 +102,4 @@ document.addEventListener('taler-execute-payment', function (e) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
//# sourceMappingURL=notify.js.map
|
@ -17,6 +17,8 @@
|
|||||||
// Script that is injected into pages in order to allow merchants pages to
|
// Script that is injected into pages in order to allow merchants pages to
|
||||||
// query the availability of Taler.
|
// query the availability of Taler.
|
||||||
|
|
||||||
|
/// <reference path="../lib/decl/chrome/chrome.d.ts" />
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
document.addEventListener("taler-checkout-probe", function(e) {
|
document.addEventListener("taler-checkout-probe", function(e) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of TALER
|
||||||
(C) 2015 GNUnet e.V.
|
(C) 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
|
||||||
@ -14,16 +14,14 @@
|
|||||||
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";
|
|
||||||
|
|
||||||
Handlebars.registerHelper('prettyAmount', function (amount) {
|
Handlebars.registerHelper('prettyAmount', function (amount) {
|
||||||
let v = amount.value + amount.fraction / 1e6;
|
let v = amount.value + amount.fraction / 1e6;
|
||||||
return v.toFixed(2) + " " + amount.currency;
|
return v.toFixed(2) + " " + amount.currency;
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('prettyAmountNoCurrency', function (amount) {
|
Handlebars.registerHelper('prettyAmountNoCurrency', function (amount) {
|
||||||
let v = amount.value + amount.fraction / 1e6;
|
let v = amount.value + amount.fraction / 1e6;
|
||||||
return v.toFixed(2);
|
return v.toFixed(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('objectStringifier', function (o) {
|
Handlebars.registerHelper('objectStringifier', function (o) {
|
18634
extension/lib/decl/lib.es6.d.ts
vendored
Normal file
18634
extension/lib/decl/lib.es6.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
20
extension/lib/decl/systemjs/systemjs.d.ts
vendored
Normal file
20
extension/lib/decl/systemjs/systemjs.d.ts
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
interface System {
|
||||||
|
import(name: string): Promise<any>;
|
||||||
|
defined: any;
|
||||||
|
amdDefine: () => void;
|
||||||
|
amdRequire: () => void;
|
||||||
|
baseURL: string;
|
||||||
|
paths: { [key: string]: string };
|
||||||
|
meta: { [key: string]: Object };
|
||||||
|
config: any;
|
||||||
|
newModule(obj: Object): any;
|
||||||
|
normalizeSync(name: string): string;
|
||||||
|
set(moduleName: string, module: any)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
declare var System: System;
|
||||||
|
|
||||||
|
declare module "systemjs" {
|
||||||
|
export = System;
|
||||||
|
}
|
41
extension/lib/emscripten/emsc.d.ts
vendored
Normal file
41
extension/lib/emscripten/emsc.d.ts
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
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 interface EmscFunGen {
|
||||||
|
(name: string,
|
||||||
|
ret: string,
|
||||||
|
args: string[]): ((...x: (number|string)[]) => any);
|
||||||
|
(name: string,
|
||||||
|
ret: 'number',
|
||||||
|
args: string[]): ((...x: (number|string)[]) => number);
|
||||||
|
(name: string,
|
||||||
|
ret: 'void',
|
||||||
|
args: string[]): ((...x: (number|string)[]) => void);
|
||||||
|
(name: string,
|
||||||
|
ret: 'string',
|
||||||
|
args: string[]): ((...x: (number|string)[]) => string);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export declare namespace Module {
|
||||||
|
var cwrap: EmscFunGen;
|
||||||
|
function _free(ptr: number);
|
||||||
|
function _malloc(n: number): number;
|
||||||
|
function Pointer_stringify(p: number, len?: number): string;
|
||||||
|
function getValue(ptr: number, type: string, noSafe?: boolean): number;
|
||||||
|
function setValue(ptr: number, value: number, type: string, noSafe?: boolean);
|
||||||
|
function writeStringToMemory(s: string, buffer: number, dontAddNull?: boolean);
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
@ -1,16 +0,0 @@
|
|||||||
"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;
|
|
||||||
}
|
|
||||||
};
|
|
6
extension/lib/refs.ts
Normal file
6
extension/lib/refs.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
// Help the TypeScript compiler find declarations.
|
||||||
|
|
||||||
|
/// <reference path="decl/lib.es6.d.ts" />
|
||||||
|
/// <reference path="decl/urijs/URIjs.d.ts" />
|
||||||
|
/// <reference path="decl/systemjs/systemjs.d.ts" />
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>
|
|
||||||
*/
|
|
||||||
'use strict';
|
|
||||||
/**
|
|
||||||
* Parse an amount that is specified like '5.42 EUR'.
|
|
||||||
* Returns a {currency,value,fraction} object or null
|
|
||||||
* if the input is invalid.
|
|
||||||
*/
|
|
||||||
function amount_parse_pretty(s) {
|
|
||||||
let pattern = /(\d+)(.\d+)?\s*([a-zA-Z]+)/;
|
|
||||||
let matches = pattern.exec(s);
|
|
||||||
if (null == matches) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
// Always succeeds due to regex
|
|
||||||
value: parseInt(matches[1]),
|
|
||||||
// Should we warn / fail on lost precision?
|
|
||||||
fraction: Math.round(parseFloat(matches[2] || "0") * 1000000),
|
|
||||||
currency: matches[3],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
function format(s, ...args) {
|
|
||||||
function r(m, n) {
|
|
||||||
let i = parseInt(n);
|
|
||||||
return args[i];
|
|
||||||
}
|
|
||||||
s = s.replace(/{{/g, '{');
|
|
||||||
s = s.replace(/}}/g, '}');
|
|
||||||
s = s.replace(/{([0-9]+)}/g, r);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
function promiseFinally(p, fn) {
|
|
||||||
return p.then((x) => { fn(); return x; })
|
|
||||||
.catch((e) => { fn(); throw e; });
|
|
||||||
}
|
|
4843
extension/lib/vendor/system.src.js
vendored
Normal file
4843
extension/lib/vendor/system.src.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -14,6 +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/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,8 +24,7 @@
|
|||||||
* @author Florian Dold
|
* @author Florian Dold
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export namespace Checkable {
|
||||||
namespace Checkable {
|
|
||||||
let chkSym = Symbol("checkable");
|
let chkSym = Symbol("checkable");
|
||||||
|
|
||||||
function checkNumber(target, prop): any {
|
function checkNumber(target, prop): any {
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of TALER
|
||||||
(C) 2015 GNUnet e.V.
|
(C) 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
|
||||||
@ -24,51 +24,6 @@
|
|||||||
* @author Florian Dold
|
* @author Florian Dold
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
namespace Db {
|
|
||||||
export interface Mint {
|
|
||||||
baseUrl: string;
|
|
||||||
keys: Keys
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CoinWithDenom {
|
|
||||||
coin: Coin;
|
|
||||||
denom: Denomination;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Keys {
|
|
||||||
denoms: Denomination[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Denomination {
|
|
||||||
value: AmountJson_interface;
|
|
||||||
denom_pub: string;
|
|
||||||
fee_withdraw: AmountJson_interface;
|
|
||||||
fee_deposit: AmountJson_interface;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PreCoin {
|
|
||||||
coinPub: string;
|
|
||||||
coinPriv: string;
|
|
||||||
reservePub: string;
|
|
||||||
denomPub: string;
|
|
||||||
blindingKey: string;
|
|
||||||
withdrawSig: string;
|
|
||||||
coinEv: string;
|
|
||||||
mintBaseUrl: string;
|
|
||||||
coinValue: AmountJson_interface;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Coin {
|
|
||||||
coinPub: string;
|
|
||||||
coinPriv: string;
|
|
||||||
denomPub: string;
|
|
||||||
denomSig: string;
|
|
||||||
currentAmount: AmountJson_interface;
|
|
||||||
mintBaseUrl: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const DB_NAME = "taler";
|
const DB_NAME = "taler";
|
||||||
const DB_VERSION = 1;
|
const DB_VERSION = 1;
|
||||||
|
|
||||||
@ -76,7 +31,7 @@ const DB_VERSION = 1;
|
|||||||
* Return a promise that resolves
|
* Return a promise that resolves
|
||||||
* to the taler wallet db.
|
* to the taler wallet db.
|
||||||
*/
|
*/
|
||||||
function openTalerDb(): Promise<IDBDatabase> {
|
export function openTalerDb(): Promise<IDBDatabase> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let req = indexedDB.open(DB_NAME, DB_VERSION);
|
let req = indexedDB.open(DB_NAME, DB_VERSION);
|
||||||
req.onerror = (e) => {
|
req.onerror = (e) => {
|
||||||
@ -107,7 +62,7 @@ function openTalerDb(): Promise<IDBDatabase> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function exportDb(db): Promise<any> {
|
export function exportDb(db): Promise<any> {
|
||||||
let dump = {
|
let dump = {
|
||||||
name: db.name,
|
name: db.name,
|
||||||
version: db.version,
|
version: db.version,
|
||||||
@ -136,3 +91,7 @@ function exportDb(db): Promise<any> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function deleteDb() {
|
||||||
|
indexedDB.deleteDatabase(DB_NAME);
|
||||||
|
}
|
@ -14,6 +14,9 @@
|
|||||||
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_interface} from "./types";
|
||||||
|
import * as EmscWrapper from "../emscripten/emsc";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* High-level interface to emscripten-compiled modules used
|
* High-level interface to emscripten-compiled modules used
|
||||||
* by the wallet.
|
* by the wallet.
|
||||||
@ -21,37 +24,8 @@
|
|||||||
* @author Florian Dold
|
* @author Florian Dold
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
declare var Module: EmscModule;
|
|
||||||
|
|
||||||
interface EmscModule {
|
|
||||||
cwrap: EmscFunGen;
|
|
||||||
_free(ptr: number);
|
|
||||||
_malloc(n: number): number;
|
|
||||||
Pointer_stringify(p: number, len?: number): string;
|
|
||||||
getValue(ptr: number, type: string, noSafe?: boolean): number;
|
|
||||||
setValue(ptr: number, value: number, type: string, noSafe?: boolean);
|
|
||||||
writeStringToMemory(s: string, buffer: number, dontAddNull?: boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EmscFunGen {
|
|
||||||
(name: string,
|
|
||||||
ret: string,
|
|
||||||
args: string[]): ((...x: (number|string)[]) => any);
|
|
||||||
(name: string,
|
|
||||||
ret: 'number',
|
|
||||||
args: string[]): ((...x: (number|string)[]) => number);
|
|
||||||
(name: string,
|
|
||||||
ret: 'void',
|
|
||||||
args: string[]): ((...x: (number|string)[]) => void);
|
|
||||||
(name: string,
|
|
||||||
ret: 'string',
|
|
||||||
args: string[]): ((...x: (number|string)[]) => string);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Size of a native pointer.
|
// Size of a native pointer.
|
||||||
const PTR_SIZE = 4;
|
const PTR_SIZE = 4;
|
||||||
|
|
||||||
@ -60,8 +34,9 @@ const GNUNET_YES = 1;
|
|||||||
const GNUNET_NO = 0;
|
const GNUNET_NO = 0;
|
||||||
const GNUNET_SYSERR = -1;
|
const GNUNET_SYSERR = -1;
|
||||||
|
|
||||||
|
let Module = EmscWrapper.Module;
|
||||||
|
|
||||||
let getEmsc: EmscFunGen = (...args) => Module.cwrap.apply(null, args);
|
let getEmsc: EmscWrapper.EmscFunGen = (...args) => Module.cwrap.apply(null, args);
|
||||||
|
|
||||||
var emsc = {
|
var emsc = {
|
||||||
free: (ptr) => Module._free(ptr),
|
free: (ptr) => Module._free(ptr),
|
||||||
@ -264,33 +239,54 @@ class DefaultArena implements Arena {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function mySetTimeout(ms: number, fn: () => void) {
|
||||||
|
// We need to use different timeouts, depending on whether
|
||||||
|
// we run in node or a web extension
|
||||||
|
if ("function" === typeof setTimeout) {
|
||||||
|
setTimeout(fn, ms);
|
||||||
|
} else {
|
||||||
|
chrome.extension.getBackgroundPage().setTimeout(fn, ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arena that destroys all its objects once control has returned to the message
|
* Arena that destroys all its objects once control has returned to the message
|
||||||
* loop and a small interval has passed.
|
* loop and a small interval has passed.
|
||||||
*/
|
*/
|
||||||
class SyncArena extends DefaultArena {
|
class SyncArena extends DefaultArena {
|
||||||
timer: Worker;
|
private isScheduled: boolean;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
let me = this;
|
}
|
||||||
this.timer = new Worker('background/timerThread.js');
|
|
||||||
this.timer.onmessage = () => {
|
pub(obj) {
|
||||||
this.destroy();
|
super.put(obj);
|
||||||
};
|
if (!this.isScheduled) {
|
||||||
//this.timer.postMessage({interval: 50});
|
this.schedule();
|
||||||
|
}
|
||||||
|
this.heap.push(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
super.destroy();
|
super.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private schedule() {
|
||||||
|
this.isScheduled = true;
|
||||||
|
mySetTimeout(50, () => {
|
||||||
|
this.isScheduled = false;
|
||||||
|
this.destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let arenaStack: Arena[] = [];
|
let arenaStack: Arena[] = [];
|
||||||
arenaStack.push(new SyncArena());
|
arenaStack.push(new SyncArena());
|
||||||
|
|
||||||
|
|
||||||
class Amount extends ArenaObject {
|
export class Amount extends ArenaObject {
|
||||||
constructor(args?: AmountJson_interface, arena?: Arena) {
|
constructor(args?: AmountJson_interface, arena?: Arena) {
|
||||||
super(arena);
|
super(arena);
|
||||||
if (args) {
|
if (args) {
|
||||||
@ -459,7 +455,7 @@ abstract class PackedArenaObject extends ArenaObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AmountNbo extends PackedArenaObject {
|
export class AmountNbo extends PackedArenaObject {
|
||||||
size() {
|
size() {
|
||||||
return 24;
|
return 24;
|
||||||
}
|
}
|
||||||
@ -474,7 +470,7 @@ class AmountNbo extends PackedArenaObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class EddsaPrivateKey extends PackedArenaObject {
|
export class EddsaPrivateKey extends PackedArenaObject {
|
||||||
static create(a?: Arena): EddsaPrivateKey {
|
static create(a?: Arena): EddsaPrivateKey {
|
||||||
let obj = new EddsaPrivateKey(a);
|
let obj = new EddsaPrivateKey(a);
|
||||||
obj.nativePtr = emscAlloc.eddsa_key_create();
|
obj.nativePtr = emscAlloc.eddsa_key_create();
|
||||||
@ -526,7 +522,7 @@ function mixinStatic(obj, method, name?: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class EddsaPublicKey extends PackedArenaObject {
|
export class EddsaPublicKey extends PackedArenaObject {
|
||||||
size() {
|
size() {
|
||||||
return 32;
|
return 32;
|
||||||
}
|
}
|
||||||
@ -560,7 +556,7 @@ function makeToCrock(encodeFn: (po: number, ps: number) => number): () => string
|
|||||||
return toCrock;
|
return toCrock;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RsaBlindingKey extends ArenaObject {
|
export class RsaBlindingKey extends ArenaObject {
|
||||||
static create(len: number, a?: Arena) {
|
static create(len: number, a?: Arena) {
|
||||||
let o = new RsaBlindingKey(a);
|
let o = new RsaBlindingKey(a);
|
||||||
o.nativePtr = emscAlloc.rsa_blinding_key_create(len);
|
o.nativePtr = emscAlloc.rsa_blinding_key_create(len);
|
||||||
@ -577,7 +573,7 @@ class RsaBlindingKey extends ArenaObject {
|
|||||||
mixinStatic(RsaBlindingKey, makeFromCrock(emscAlloc.rsa_blinding_key_decode));
|
mixinStatic(RsaBlindingKey, makeFromCrock(emscAlloc.rsa_blinding_key_decode));
|
||||||
|
|
||||||
|
|
||||||
class HashCode extends PackedArenaObject {
|
export class HashCode extends PackedArenaObject {
|
||||||
size() {
|
size() {
|
||||||
return 64;
|
return 64;
|
||||||
}
|
}
|
||||||
@ -608,7 +604,7 @@ class HashCode extends PackedArenaObject {
|
|||||||
mixinStatic(HashCode, fromCrock);
|
mixinStatic(HashCode, fromCrock);
|
||||||
|
|
||||||
|
|
||||||
class ByteArray extends PackedArenaObject {
|
export class ByteArray extends PackedArenaObject {
|
||||||
private allocatedSize: number;
|
private allocatedSize: number;
|
||||||
|
|
||||||
size() {
|
size() {
|
||||||
@ -646,7 +642,7 @@ class ByteArray extends PackedArenaObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class EccSignaturePurpose extends PackedArenaObject {
|
export class EccSignaturePurpose extends PackedArenaObject {
|
||||||
size() {
|
size() {
|
||||||
return this.payloadSize + 8;
|
return this.payloadSize + 8;
|
||||||
}
|
}
|
||||||
@ -734,7 +730,7 @@ abstract class SignatureStruct {
|
|||||||
|
|
||||||
|
|
||||||
// It's redundant, but more type safe.
|
// It's redundant, but more type safe.
|
||||||
interface WithdrawRequestPS_Args {
|
export interface WithdrawRequestPS_Args {
|
||||||
reserve_pub: EddsaPublicKey;
|
reserve_pub: EddsaPublicKey;
|
||||||
amount_with_fee: AmountNbo;
|
amount_with_fee: AmountNbo;
|
||||||
withdraw_fee: AmountNbo;
|
withdraw_fee: AmountNbo;
|
||||||
@ -743,7 +739,7 @@ interface WithdrawRequestPS_Args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class WithdrawRequestPS extends SignatureStruct {
|
export class WithdrawRequestPS extends SignatureStruct {
|
||||||
constructor(w: WithdrawRequestPS_Args) {
|
constructor(w: WithdrawRequestPS_Args) {
|
||||||
super(w);
|
super(w);
|
||||||
}
|
}
|
||||||
@ -764,7 +760,7 @@ class WithdrawRequestPS extends SignatureStruct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AbsoluteTimeNbo extends PackedArenaObject {
|
export class AbsoluteTimeNbo extends PackedArenaObject {
|
||||||
static fromTalerString(s: string): AbsoluteTimeNbo {
|
static fromTalerString(s: string): AbsoluteTimeNbo {
|
||||||
let x = new AbsoluteTimeNbo();
|
let x = new AbsoluteTimeNbo();
|
||||||
x.alloc();
|
x.alloc();
|
||||||
@ -795,7 +791,7 @@ function set64(p: number, n: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class UInt64 extends PackedArenaObject {
|
export class UInt64 extends PackedArenaObject {
|
||||||
static fromNumber(n: number): UInt64 {
|
static fromNumber(n: number): UInt64 {
|
||||||
let x = new UInt64();
|
let x = new UInt64();
|
||||||
x.alloc();
|
x.alloc();
|
||||||
@ -810,7 +806,7 @@ class UInt64 extends PackedArenaObject {
|
|||||||
|
|
||||||
|
|
||||||
// It's redundant, but more type safe.
|
// It's redundant, but more type safe.
|
||||||
interface DepositRequestPS_Args {
|
export interface DepositRequestPS_Args {
|
||||||
h_contract: HashCode;
|
h_contract: HashCode;
|
||||||
h_wire: HashCode;
|
h_wire: HashCode;
|
||||||
timestamp: AbsoluteTimeNbo;
|
timestamp: AbsoluteTimeNbo;
|
||||||
@ -823,7 +819,7 @@ interface DepositRequestPS_Args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class DepositRequestPS extends SignatureStruct {
|
export class DepositRequestPS extends SignatureStruct {
|
||||||
constructor(w: DepositRequestPS_Args) {
|
constructor(w: DepositRequestPS_Args) {
|
||||||
super(w);
|
super(w);
|
||||||
}
|
}
|
||||||
@ -865,7 +861,7 @@ function makeEncode(encodeFn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class RsaPublicKey extends ArenaObject implements Encodeable {
|
export class RsaPublicKey extends ArenaObject implements Encodeable {
|
||||||
static fromCrock: (s: string, a?: Arena) => RsaPublicKey;
|
static fromCrock: (s: string, a?: Arena) => RsaPublicKey;
|
||||||
|
|
||||||
toCrock() {
|
toCrock() {
|
||||||
@ -883,14 +879,14 @@ mixinStatic(RsaPublicKey, makeFromCrock(emscAlloc.rsa_public_key_decode));
|
|||||||
mixin(RsaPublicKey, makeEncode(emscAlloc.rsa_public_key_encode));
|
mixin(RsaPublicKey, makeEncode(emscAlloc.rsa_public_key_encode));
|
||||||
|
|
||||||
|
|
||||||
class EddsaSignature extends PackedArenaObject {
|
export class EddsaSignature extends PackedArenaObject {
|
||||||
size() {
|
size() {
|
||||||
return 64;
|
return 64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class RsaSignature extends ArenaObject implements Encodeable{
|
export class RsaSignature extends ArenaObject implements Encodeable{
|
||||||
static fromCrock: (s: string, a?: Arena) => RsaSignature;
|
static fromCrock: (s: string, a?: Arena) => RsaSignature;
|
||||||
|
|
||||||
encode: (arena?: Arena) => ByteArray;
|
encode: (arena?: Arena) => ByteArray;
|
||||||
@ -904,7 +900,7 @@ mixinStatic(RsaSignature, makeFromCrock(emscAlloc.rsa_signature_decode));
|
|||||||
mixin(RsaSignature, makeEncode(emscAlloc.rsa_signature_encode));
|
mixin(RsaSignature, makeEncode(emscAlloc.rsa_signature_encode));
|
||||||
|
|
||||||
|
|
||||||
function rsaBlind(hashCode: HashCode,
|
export function rsaBlind(hashCode: HashCode,
|
||||||
blindingKey: RsaBlindingKey,
|
blindingKey: RsaBlindingKey,
|
||||||
pkey: RsaPublicKey,
|
pkey: RsaPublicKey,
|
||||||
arena?: Arena): ByteArray {
|
arena?: Arena): ByteArray {
|
||||||
@ -917,7 +913,7 @@ function rsaBlind(hashCode: HashCode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function eddsaSign(purpose: EccSignaturePurpose,
|
export function eddsaSign(purpose: EccSignaturePurpose,
|
||||||
priv: EddsaPrivateKey,
|
priv: EddsaPrivateKey,
|
||||||
a?: Arena): EddsaSignature {
|
a?: Arena): EddsaSignature {
|
||||||
let sig = new EddsaSignature(a);
|
let sig = new EddsaSignature(a);
|
||||||
@ -930,7 +926,7 @@ function eddsaSign(purpose: EccSignaturePurpose,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function rsaUnblind(sig: RsaSignature,
|
export function rsaUnblind(sig: RsaSignature,
|
||||||
bk: RsaBlindingKey,
|
bk: RsaBlindingKey,
|
||||||
pk: RsaPublicKey,
|
pk: RsaPublicKey,
|
||||||
a?: Arena): RsaSignature {
|
a?: Arena): RsaSignature {
|
@ -22,13 +22,15 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
interface HttpResponse {
|
|
||||||
|
|
||||||
|
export interface HttpResponse {
|
||||||
status: number;
|
status: number;
|
||||||
responseText: string;
|
responseText: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class BrowserHttpLib {
|
export class BrowserHttpLib {
|
||||||
req(method: string,
|
req(method: string,
|
||||||
url: string|uri.URI,
|
url: string|uri.URI,
|
||||||
options?: any): Promise<HttpResponse> {
|
options?: any): Promise<HttpResponse> {
|
||||||
@ -76,7 +78,7 @@ class BrowserHttpLib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class RequestException {
|
export class RequestException {
|
||||||
constructor(detail) {
|
constructor(detail) {
|
||||||
|
|
||||||
}
|
}
|
@ -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/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// <reference path="../decl/chrome/chrome.d.ts" />
|
/// <reference path="../decl/urijs/URIjs.d.ts" />
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,7 +26,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
|
||||||
function Query(db) {
|
export function Query(db) {
|
||||||
return new QueryRoot(db);
|
return new QueryRoot(db);
|
||||||
}
|
}
|
||||||
|
|
@ -6,5 +6,5 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
onmessage = function(e) {
|
onmessage = function(e) {
|
||||||
self.setInterval(() => postMessage(true), e.data.interval);
|
self.setInterval(() => postMessage(true, "timerThread"), e.data.interval);
|
||||||
};
|
};
|
109
extension/lib/wallet/types.ts
Normal file
109
extension/lib/wallet/types.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
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/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// TODO: factor into multiple files
|
||||||
|
|
||||||
|
export interface Mint {
|
||||||
|
baseUrl: string;
|
||||||
|
keys: Keys
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CoinWithDenom {
|
||||||
|
coin: Coin;
|
||||||
|
denom: Denomination;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Keys {
|
||||||
|
denoms: Denomination[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Denomination {
|
||||||
|
value: AmountJson_interface;
|
||||||
|
denom_pub: string;
|
||||||
|
fee_withdraw: AmountJson_interface;
|
||||||
|
fee_deposit: AmountJson_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PreCoin {
|
||||||
|
coinPub: string;
|
||||||
|
coinPriv: string;
|
||||||
|
reservePub: string;
|
||||||
|
denomPub: string;
|
||||||
|
blindingKey: string;
|
||||||
|
withdrawSig: string;
|
||||||
|
coinEv: string;
|
||||||
|
mintBaseUrl: string;
|
||||||
|
coinValue: AmountJson_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Coin {
|
||||||
|
coinPub: string;
|
||||||
|
coinPriv: string;
|
||||||
|
denomPub: string;
|
||||||
|
denomSig: string;
|
||||||
|
currentAmount: AmountJson_interface;
|
||||||
|
mintBaseUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface AmountJson_interface {
|
||||||
|
value: number;
|
||||||
|
fraction: number
|
||||||
|
currency: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConfirmReserveRequest {
|
||||||
|
/**
|
||||||
|
* Name of the form field for the amount.
|
||||||
|
*/
|
||||||
|
field_amount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the form field for the reserve public key.
|
||||||
|
*/
|
||||||
|
field_reserve_pub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the form field for the reserve public key.
|
||||||
|
*/
|
||||||
|
field_mint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The actual amount in string form.
|
||||||
|
* TODO: where is this format specified?
|
||||||
|
*/
|
||||||
|
amount_str;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target URL for the reserve creation request.
|
||||||
|
*/
|
||||||
|
post_url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mint URL where the bank should create the reserve.
|
||||||
|
*/
|
||||||
|
mint;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ConfirmReserveResponse {
|
||||||
|
backlink: string;
|
||||||
|
success: boolean;
|
||||||
|
status: number;
|
||||||
|
text: string;
|
||||||
|
}
|
@ -21,8 +21,35 @@
|
|||||||
* @author Florian Dold
|
* @author Florian Dold
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {Amount} from "./emscriptif"
|
||||||
|
import {AmountJson_interface} from "./types";
|
||||||
|
import {CoinWithDenom} from "./types";
|
||||||
|
import {DepositRequestPS_Args} from "./emscriptif";
|
||||||
|
import {HashCode} from "./emscriptif";
|
||||||
|
import {EddsaPublicKey} from "./emscriptif";
|
||||||
|
import {Coin} from "./types";
|
||||||
|
import {AbsoluteTimeNbo} from "./emscriptif";
|
||||||
|
import {UInt64} from "./emscriptif";
|
||||||
|
import {DepositRequestPS} from "./emscriptif";
|
||||||
|
import {eddsaSign} from "./emscriptif";
|
||||||
|
import {EddsaPrivateKey} from "./emscriptif";
|
||||||
|
import {ConfirmReserveRequest} from "./types";
|
||||||
|
import {ConfirmReserveResponse} from "./types";
|
||||||
|
import {RsaPublicKey} from "./emscriptif";
|
||||||
|
import {Denomination} from "./types";
|
||||||
|
import {RsaBlindingKey} from "./emscriptif";
|
||||||
|
import {ByteArray} from "./emscriptif";
|
||||||
|
import {rsaBlind} from "./emscriptif";
|
||||||
|
import {WithdrawRequestPS} from "./emscriptif";
|
||||||
|
import {PreCoin} from "./types";
|
||||||
|
import {rsaUnblind} from "./emscriptif";
|
||||||
|
import {RsaSignature} from "./emscriptif";
|
||||||
|
import {Mint} from "./types";
|
||||||
|
import {Checkable} from "./checkable";
|
||||||
|
import {HttpResponse} from "./http";
|
||||||
|
import {RequestException} from "./http";
|
||||||
|
import {Query} from "./query";
|
||||||
|
|
||||||
/// <reference path="../decl/urijs/URIjs.d.ts" />
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
@Checkable.Class
|
@Checkable.Class
|
||||||
@ -60,11 +87,6 @@ class CoinPaySig {
|
|||||||
static check: (v: any) => CoinPaySig;
|
static check: (v: any) => CoinPaySig;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AmountJson_interface {
|
|
||||||
value: number;
|
|
||||||
fraction: number
|
|
||||||
currency: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ConfirmPayRequest {
|
interface ConfirmPayRequest {
|
||||||
merchantPageUrl: string;
|
merchantPageUrl: string;
|
||||||
@ -72,7 +94,7 @@ interface ConfirmPayRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface MintCoins {
|
interface MintCoins {
|
||||||
[mintUrl: string]: Db.CoinWithDenom[];
|
[mintUrl: string]: CoinWithDenom[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -136,49 +158,13 @@ interface PaymentResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface ConfirmReserveRequest {
|
export interface Badge {
|
||||||
/**
|
setText(s: string): void;
|
||||||
* Name of the form field for the amount.
|
setColor(c: string): void;
|
||||||
*/
|
|
||||||
field_amount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of the form field for the reserve public key.
|
|
||||||
*/
|
|
||||||
field_reserve_pub;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of the form field for the reserve public key.
|
|
||||||
*/
|
|
||||||
field_mint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The actual amount in string form.
|
|
||||||
* TODO: where is this format specified?
|
|
||||||
*/
|
|
||||||
amount_str;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Target URL for the reserve creation request.
|
|
||||||
*/
|
|
||||||
post_url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mint URL where the bank should create the reserve.
|
|
||||||
*/
|
|
||||||
mint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface ConfirmReserveResponse {
|
type PayCoinInfo = Array<{ updatedCoin: Coin, sig: CoinPaySig_interface }>;
|
||||||
backlink: string;
|
|
||||||
success: boolean;
|
|
||||||
status: number;
|
|
||||||
text: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type PayCoinInfo = Array<{ updatedCoin: Db.Coin, sig: CoinPaySig_interface }>;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -208,11 +194,6 @@ interface HttpRequestLibrary {
|
|||||||
postForm(url: string|uri.URI, form): Promise<HttpResponse>;
|
postForm(url: string|uri.URI, form): Promise<HttpResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Badge {
|
|
||||||
setText(s: string): void;
|
|
||||||
setColor(c: string): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function copy(o) {
|
function copy(o) {
|
||||||
return JSON.parse(JSON.stringify(o));
|
return JSON.parse(JSON.stringify(o));
|
||||||
@ -227,7 +208,7 @@ function rankDenom(denom1: any, denom2: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Wallet {
|
export class Wallet {
|
||||||
private db: IDBDatabase;
|
private db: IDBDatabase;
|
||||||
private http: HttpRequestLibrary;
|
private http: HttpRequestLibrary;
|
||||||
private badge: Badge;
|
private badge: Badge;
|
||||||
@ -239,7 +220,7 @@ class Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static signDeposit(offer: Offer,
|
static signDeposit(offer: Offer,
|
||||||
cds: Db.CoinWithDenom[]): PayCoinInfo {
|
cds: CoinWithDenom[]): PayCoinInfo {
|
||||||
let ret = [];
|
let ret = [];
|
||||||
let amountSpent = Amount.getZero(cds[0].coin.currentAmount.currency);
|
let amountSpent = Amount.getZero(cds[0].coin.currentAmount.currency);
|
||||||
let amountRemaining = new Amount(offer.contract.amount);
|
let amountRemaining = new Amount(offer.contract.amount);
|
||||||
@ -349,7 +330,7 @@ class Wallet {
|
|||||||
let minAmount = new Amount(paymentAmount);
|
let minAmount = new Amount(paymentAmount);
|
||||||
let accFee = new Amount(coins[0].c.denom.fee_deposit);
|
let accFee = new Amount(coins[0].c.denom.fee_deposit);
|
||||||
let accAmount = Amount.getZero(coins[0].c.coin.currentAmount.currency);
|
let accAmount = Amount.getZero(coins[0].c.coin.currentAmount.currency);
|
||||||
let usableCoins: Db.CoinWithDenom[] = [];
|
let usableCoins: CoinWithDenom[] = [];
|
||||||
nextCoin:
|
nextCoin:
|
||||||
for (let i = 0; i < coins.length; i++) {
|
for (let i = 0; i < coins.length; i++) {
|
||||||
let coinAmount = new Amount(coins[i].c.coin.currentAmount);
|
let coinAmount = new Amount(coins[i].c.coin.currentAmount);
|
||||||
@ -488,8 +469,8 @@ class Wallet {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
withdrawPrepare(denom: Db.Denomination,
|
withdrawPrepare(denom: Denomination,
|
||||||
reserve: Reserve): Promise<Db.PreCoin> {
|
reserve: Reserve): Promise<PreCoin> {
|
||||||
let reservePriv = new EddsaPrivateKey();
|
let reservePriv = new EddsaPrivateKey();
|
||||||
reservePriv.loadCrock(reserve.reserve_priv);
|
reservePriv.loadCrock(reserve.reserve_priv);
|
||||||
let reservePub = new EddsaPublicKey();
|
let reservePub = new EddsaPublicKey();
|
||||||
@ -520,7 +501,7 @@ class Wallet {
|
|||||||
|
|
||||||
var sig = eddsaSign(withdrawRequest.toPurpose(), reservePriv);
|
var sig = eddsaSign(withdrawRequest.toPurpose(), reservePriv);
|
||||||
|
|
||||||
let preCoin: Db.PreCoin = {
|
let preCoin: PreCoin = {
|
||||||
reservePub: reservePub.toCrock(),
|
reservePub: reservePub.toCrock(),
|
||||||
blindingKey: blindingFactor.toCrock(),
|
blindingKey: blindingFactor.toCrock(),
|
||||||
coinPub: coinPub.toCrock(),
|
coinPub: coinPub.toCrock(),
|
||||||
@ -536,7 +517,7 @@ class Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
withdrawExecute(pc: Db.PreCoin): Promise<Db.Coin> {
|
withdrawExecute(pc: PreCoin): Promise<Coin> {
|
||||||
return Query(this.db)
|
return Query(this.db)
|
||||||
.get("reserves", pc.reservePub)
|
.get("reserves", pc.reservePub)
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
@ -559,7 +540,7 @@ class Wallet {
|
|||||||
let denomSig = rsaUnblind(RsaSignature.fromCrock(r.ev_sig),
|
let denomSig = rsaUnblind(RsaSignature.fromCrock(r.ev_sig),
|
||||||
RsaBlindingKey.fromCrock(pc.blindingKey),
|
RsaBlindingKey.fromCrock(pc.blindingKey),
|
||||||
RsaPublicKey.fromCrock(pc.denomPub));
|
RsaPublicKey.fromCrock(pc.denomPub));
|
||||||
let coin: Db.Coin = {
|
let coin: Coin = {
|
||||||
coinPub: pc.coinPub,
|
coinPub: pc.coinPub,
|
||||||
coinPriv: pc.coinPriv,
|
coinPriv: pc.coinPriv,
|
||||||
denomPub: pc.denomPub,
|
denomPub: pc.denomPub,
|
||||||
@ -591,7 +572,7 @@ class Wallet {
|
|||||||
.then(doBadge.bind(this));
|
.then(doBadge.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
storeCoin(coin: Db.Coin) {
|
storeCoin(coin: Coin) {
|
||||||
Query(this.db)
|
Query(this.db)
|
||||||
.delete("precoins", coin.coinPub)
|
.delete("precoins", coin.coinPub)
|
||||||
.add("coins", coin)
|
.add("coins", coin)
|
||||||
@ -688,7 +669,7 @@ class Wallet {
|
|||||||
if (!mintKeysJson) {
|
if (!mintKeysJson) {
|
||||||
throw new RequestException({url: reqUrl, hint: "keys invalid"});
|
throw new RequestException({url: reqUrl, hint: "keys invalid"});
|
||||||
}
|
}
|
||||||
let mint: Db.Mint = {
|
let mint: Mint = {
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
keys: mintKeysJson
|
keys: mintKeysJson
|
||||||
};
|
};
|
||||||
@ -698,7 +679,7 @@ class Wallet {
|
|||||||
|
|
||||||
|
|
||||||
getBalances(): Promise<any> {
|
getBalances(): Promise<any> {
|
||||||
function collectBalances(c: Db.Coin, byCurrency) {
|
function collectBalances(c: Coin, byCurrency) {
|
||||||
let acc: AmountJson_interface = byCurrency[c.currentAmount.currency];
|
let acc: AmountJson_interface = byCurrency[c.currentAmount.currency];
|
||||||
if (!acc) {
|
if (!acc) {
|
||||||
acc = Amount.getZero(c.currentAmount.currency).toJson();
|
acc = Amount.getZero(c.currentAmount.currency).toJson();
|
144
extension/lib/wallet/wxmessaging.js
Normal file
144
extension/lib/wallet/wxmessaging.js
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
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/>
|
||||||
|
*/
|
||||||
|
System.register(["./wallet", "./db", "./http"], function(exports_1) {
|
||||||
|
"use strict";
|
||||||
|
var wallet_1, db_1, db_2, db_3, http_1;
|
||||||
|
var ChromeBadge;
|
||||||
|
function makeHandlers(wallet) {
|
||||||
|
return (_a = {},
|
||||||
|
_a["balances"] = function (db, detail, sendResponse) {
|
||||||
|
wallet.getBalances().then(sendResponse);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
_a["dump-db"] = function (db, detail, sendResponse) {
|
||||||
|
db_1.exportDb(db).then(sendResponse);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
_a["reset"] = function (db, detail, sendResponse) {
|
||||||
|
var tx = db.transaction(db.objectStoreNames, 'readwrite');
|
||||||
|
for (var i = 0; i < db.objectStoreNames.length; i++) {
|
||||||
|
tx.objectStore(db.objectStoreNames[i]).clear();
|
||||||
|
}
|
||||||
|
db_2.deleteDb();
|
||||||
|
chrome.browserAction.setBadgeText({ text: "" });
|
||||||
|
console.log("reset done");
|
||||||
|
// Response is synchronous
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
_a["confirm-reserve"] = function (db, detail, sendResponse) {
|
||||||
|
// TODO: make it a checkable
|
||||||
|
var req = {
|
||||||
|
field_amount: detail.field_amount,
|
||||||
|
field_mint: detail.field_mint,
|
||||||
|
field_reserve_pub: detail.field_reserve_pub,
|
||||||
|
post_url: detail.post_url,
|
||||||
|
mint: detail.mint,
|
||||||
|
amount_str: detail.amount_str
|
||||||
|
};
|
||||||
|
wallet.confirmReserve(req)
|
||||||
|
.then(function (resp) {
|
||||||
|
if (resp.success) {
|
||||||
|
resp.backlink = chrome.extension.getURL("pages/reserve-success.html");
|
||||||
|
}
|
||||||
|
sendResponse(resp);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
_a["confirm-pay"] = function (db, detail, sendResponse) {
|
||||||
|
wallet.confirmPay(detail.offer, detail.merchantPageUrl)
|
||||||
|
.then(function () {
|
||||||
|
sendResponse({ success: true });
|
||||||
|
})
|
||||||
|
.catch(function (e) {
|
||||||
|
sendResponse({ error: e.message });
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
_a["execute-payment"] = function (db, detail, sendResponse) {
|
||||||
|
wallet.doPayment(detail.H_contract)
|
||||||
|
.then(function (r) {
|
||||||
|
sendResponse({
|
||||||
|
success: true,
|
||||||
|
payUrl: r.payUrl,
|
||||||
|
payReq: r.payReq
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function (e) {
|
||||||
|
sendResponse({ success: false, error: e.message });
|
||||||
|
});
|
||||||
|
// async sendResponse
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
_a
|
||||||
|
);
|
||||||
|
var _a;
|
||||||
|
}
|
||||||
|
function wxMain() {
|
||||||
|
chrome.browserAction.setBadgeText({ text: "" });
|
||||||
|
db_3.openTalerDb().then(function (db) {
|
||||||
|
var http = new http_1.BrowserHttpLib();
|
||||||
|
var badge = new ChromeBadge();
|
||||||
|
var wallet = new wallet_1.Wallet(db, http, badge);
|
||||||
|
var handlers = makeHandlers(wallet);
|
||||||
|
wallet.updateBadge();
|
||||||
|
chrome.runtime.onMessage.addListener(function (req, sender, onresponse) {
|
||||||
|
if (req.type in handlers) {
|
||||||
|
return handlers[req.type](db, req.detail, onresponse);
|
||||||
|
}
|
||||||
|
console.error(format("Request type {1} unknown, req {0}", JSON.stringify(req), req.type));
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports_1("wxMain", wxMain);
|
||||||
|
return {
|
||||||
|
setters:[
|
||||||
|
function (wallet_1_1) {
|
||||||
|
wallet_1 = wallet_1_1;
|
||||||
|
},
|
||||||
|
function (db_1_1) {
|
||||||
|
db_1 = db_1_1;
|
||||||
|
db_2 = db_1_1;
|
||||||
|
db_3 = db_1_1;
|
||||||
|
},
|
||||||
|
function (http_1_1) {
|
||||||
|
http_1 = http_1_1;
|
||||||
|
}],
|
||||||
|
execute: function() {
|
||||||
|
/**
|
||||||
|
* Messaging for the WebExtensions wallet. Should contain
|
||||||
|
* parts that are specific for WebExtensions, but as little business
|
||||||
|
* logic as possible.
|
||||||
|
* @module Messaging
|
||||||
|
* @author Florian Dold
|
||||||
|
*/
|
||||||
|
"use strict";
|
||||||
|
ChromeBadge = (function () {
|
||||||
|
function ChromeBadge() {
|
||||||
|
}
|
||||||
|
ChromeBadge.prototype.setText = function (s) {
|
||||||
|
chrome.browserAction.setBadgeText({ text: s });
|
||||||
|
};
|
||||||
|
ChromeBadge.prototype.setColor = function (c) {
|
||||||
|
chrome.browserAction.setBadgeBackgroundColor({ color: c });
|
||||||
|
};
|
||||||
|
return ChromeBadge;
|
||||||
|
}());
|
||||||
|
wxMain();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=wxmessaging.js.map
|
@ -15,6 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import {ConfirmReserveRequest} from "./types";
|
||||||
|
import {Wallet} from "./wallet";
|
||||||
|
import {exportDb} from "./db";
|
||||||
|
import {deleteDb} from "./db";
|
||||||
|
import {openTalerDb} from "./db";
|
||||||
|
import {BrowserHttpLib} from "./http";
|
||||||
|
import {Badge} from "./wallet";
|
||||||
/**
|
/**
|
||||||
* Messaging for the WebExtensions wallet. Should contain
|
* Messaging for the WebExtensions wallet. Should contain
|
||||||
* parts that are specific for WebExtensions, but as little business
|
* parts that are specific for WebExtensions, but as little business
|
||||||
@ -40,7 +47,8 @@ function makeHandlers(wallet) {
|
|||||||
for (let i = 0; i < db.objectStoreNames.length; i++) {
|
for (let i = 0; i < db.objectStoreNames.length; i++) {
|
||||||
tx.objectStore(db.objectStoreNames[i]).clear();
|
tx.objectStore(db.objectStoreNames[i]).clear();
|
||||||
}
|
}
|
||||||
indexedDB.deleteDatabase(DB_NAME);
|
deleteDb();
|
||||||
|
|
||||||
chrome.browserAction.setBadgeText({text: ""});
|
chrome.browserAction.setBadgeText({text: ""});
|
||||||
console.log("reset done");
|
console.log("reset done");
|
||||||
// Response is synchronous
|
// Response is synchronous
|
||||||
@ -94,7 +102,7 @@ function makeHandlers(wallet) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChromeBadge {
|
class ChromeBadge implements Badge {
|
||||||
setText(s: string) {
|
setText(s: string) {
|
||||||
chrome.browserAction.setBadgeText({text: s});
|
chrome.browserAction.setBadgeText({text: s});
|
||||||
}
|
}
|
||||||
@ -105,7 +113,7 @@ class ChromeBadge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function wxMain() {
|
export function wxMain() {
|
||||||
chrome.browserAction.setBadgeText({text: ""});
|
chrome.browserAction.setBadgeText({text: ""});
|
||||||
|
|
||||||
openTalerDb().then((db) => {
|
openTalerDb().then((db) => {
|
@ -26,9 +26,10 @@
|
|||||||
{
|
{
|
||||||
"matches": ["*://*/*"],
|
"matches": ["*://*/*"],
|
||||||
"js": [
|
"js": [
|
||||||
"content_scripts/notify.js",
|
"lib/vendor/system.src.js",
|
||||||
"lib/URI.js",
|
"lib/vendor/URI.js",
|
||||||
"lib/util.js"
|
"lib/util.js",
|
||||||
|
"content_scripts/notify.js"
|
||||||
],
|
],
|
||||||
"run_at": "document_start"
|
"run_at": "document_start"
|
||||||
}
|
}
|
||||||
@ -41,16 +42,12 @@
|
|||||||
|
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": [
|
"scripts": [
|
||||||
|
"lib/vendor/URI.js",
|
||||||
|
"lib/vendor/handlebars-v4.0.5.js",
|
||||||
"lib/util.js",
|
"lib/util.js",
|
||||||
"lib/URI.js",
|
"lib/emscripten/libwrapper.js",
|
||||||
"background/checkable.js",
|
"lib/vendor/system.src.js",
|
||||||
"background/libwrapper.js",
|
"background/main.js"
|
||||||
"background/emscriptif.js",
|
|
||||||
"background/db.js",
|
|
||||||
"background/query.js",
|
|
||||||
"background/messaging.js",
|
|
||||||
"background/http.js",
|
|
||||||
"background/wallet.js"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
20
extension/package.json
Normal file
20
extension/package.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "taler-wallet",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "wxwallet.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "mocha --delay"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://git.taler.net/wallet.git"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"better-assert": "^1.0.2",
|
||||||
|
"mocha": "^2.3.4",
|
||||||
|
"systemjs": "^0.19.14"
|
||||||
|
}
|
||||||
|
}
|
@ -3,8 +3,8 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Taler Wallet: Confirm Reserve Creation</title>
|
<title>Taler Wallet: Confirm Reserve Creation</title>
|
||||||
<script src="../lib/URI.js"></script>
|
<script src="../lib/vendor/URI.js"></script>
|
||||||
<script src="../lib/handlebars-v4.0.5.js"></script>
|
<script src="../lib/vendor/handlebars-v4.0.5.js"></script>
|
||||||
<script src="../lib/commonHelpers.js"></script>
|
<script src="../lib/commonHelpers.js"></script>
|
||||||
<script src="confirm-contract.js"></script>
|
<script src="confirm-contract.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="../style/wallet.css">
|
<link rel="stylesheet" type="text/css" href="../style/wallet.css">
|
||||||
|
@ -13,13 +13,13 @@
|
|||||||
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="../decl/handlebars/handlebars.d.ts" />
|
/// <reference path="../lib/decl/handlebars/handlebars.d.ts" />
|
||||||
"use strict";
|
"use strict";
|
||||||
let url = URI(document.location.href);
|
var url = URI(document.location.href);
|
||||||
let query = URI.parseQuery(url.query());
|
var query = URI.parseQuery(url.query());
|
||||||
let $_ = (x) => document.getElementById(x);
|
var $_ = function (x) { return document.getElementById(x); };
|
||||||
function renderContract(contract) {
|
function renderContract(contract) {
|
||||||
let showAmount = document.getElementById("show-amount");
|
var showAmount = document.getElementById("show-amount");
|
||||||
$_('merchant-name').innerText = contract.merchant.name;
|
$_('merchant-name').innerText = contract.merchant.name;
|
||||||
}
|
}
|
||||||
function clone(obj) {
|
function clone(obj) {
|
||||||
@ -27,26 +27,26 @@ function clone(obj) {
|
|||||||
return JSON.parse(JSON.stringify(obj));
|
return JSON.parse(JSON.stringify(obj));
|
||||||
}
|
}
|
||||||
Handlebars.registerHelper('prettyAmount', function (amount) {
|
Handlebars.registerHelper('prettyAmount', function (amount) {
|
||||||
let v = amount.value + amount.fraction / 10e6;
|
var v = amount.value + amount.fraction / 10e6;
|
||||||
return v.toFixed(2) + " " + amount.currency;
|
return v.toFixed(2) + " " + amount.currency;
|
||||||
});
|
});
|
||||||
document.addEventListener("DOMContentLoaded", (e) => {
|
document.addEventListener("DOMContentLoaded", function (e) {
|
||||||
let offer = JSON.parse(query.offer);
|
var offer = JSON.parse(query.offer);
|
||||||
console.dir(offer);
|
console.dir(offer);
|
||||||
let source = $_("contract-template").innerHTML;
|
var source = $_("contract-template").innerHTML;
|
||||||
let template = Handlebars.compile(source);
|
var template = Handlebars.compile(source);
|
||||||
$_("render-contract").innerHTML = template(offer.contract);
|
$_("render-contract").innerHTML = template(offer.contract);
|
||||||
document.getElementById("confirm-pay").addEventListener("click", (e) => {
|
document.getElementById("confirm-pay").addEventListener("click", function (e) {
|
||||||
console.log("Query:", JSON.stringify(query));
|
console.log("Query:", JSON.stringify(query));
|
||||||
let d = {
|
var d = {
|
||||||
offer: JSON.parse(query.offer),
|
offer: JSON.parse(query.offer),
|
||||||
merchantPageUrl: query.merchantPageUrl
|
merchantPageUrl: query.merchantPageUrl
|
||||||
};
|
};
|
||||||
chrome.runtime.sendMessage({ type: 'confirm-pay', detail: d }, (resp) => {
|
chrome.runtime.sendMessage({ type: 'confirm-pay', detail: d }, function (resp) {
|
||||||
if (!resp.success) {
|
if (!resp.success) {
|
||||||
let source = $_("error-template").innerHTML;
|
var source_1 = $_("error-template").innerHTML;
|
||||||
let template = Handlebars.compile(source);
|
var template_1 = Handlebars.compile(source_1);
|
||||||
$_("status").innerHTML = template(resp);
|
$_("status").innerHTML = template_1(resp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
document.location.href = URI(d.offer.exec_url)
|
document.location.href = URI(d.offer.exec_url)
|
||||||
@ -56,3 +56,4 @@ document.addEventListener("DOMContentLoaded", (e) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
//# sourceMappingURL=confirm-contract.js.map
|
@ -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/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// <reference path="../decl/handlebars/handlebars.d.ts" />
|
/// <reference path="../lib/decl/handlebars/handlebars.d.ts" />
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
let url = URI(document.location.href);
|
let url = URI(document.location.href);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Taler Wallet: Select Taler Provider</title>
|
<title>Taler Wallet: Select Taler Provider</title>
|
||||||
<script src="../lib/URI.js"></script>
|
<script src="../lib/vendor/URI.js"></script>
|
||||||
<script src="../lib/polyfill-react.js"></script>
|
<script src="../lib/polyfill-react.js"></script>
|
||||||
<script src="confirm-create-reserve.js"></script>
|
<script src="confirm-create-reserve.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="../style/wallet.css">
|
<link rel="stylesheet" type="text/css" href="../style/wallet.css">
|
||||||
|
@ -16,12 +16,12 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
var ConfirmCreateReserve;
|
var ConfirmCreateReserve;
|
||||||
(function (ConfirmCreateReserve) {
|
(function (ConfirmCreateReserve) {
|
||||||
let url = URI(document.location.href);
|
var url = URI(document.location.href);
|
||||||
let query = URI.parseQuery(url.query());
|
var query = URI.parseQuery(url.query());
|
||||||
function updateAmount() {
|
function updateAmount() {
|
||||||
let showAmount = document.getElementById("show-amount");
|
var showAmount = document.getElementById("show-amount");
|
||||||
console.log("Query is " + JSON.stringify(query));
|
console.log("Query is " + JSON.stringify(query));
|
||||||
let s = query.amount_str;
|
var s = query.amount_str;
|
||||||
if (!s) {
|
if (!s) {
|
||||||
document.body.innerHTML = "Oops, something went wrong.";
|
document.body.innerHTML = "Oops, something went wrong.";
|
||||||
return;
|
return;
|
||||||
@ -32,25 +32,21 @@ var ConfirmCreateReserve;
|
|||||||
// This is faster than it looks ...
|
// This is faster than it looks ...
|
||||||
return JSON.parse(JSON.stringify(obj));
|
return JSON.parse(JSON.stringify(obj));
|
||||||
}
|
}
|
||||||
document.addEventListener("DOMContentLoaded", (e) => {
|
document.addEventListener("DOMContentLoaded", function (e) {
|
||||||
updateAmount();
|
updateAmount();
|
||||||
document.getElementById("confirm").addEventListener("click", (e) => {
|
document.getElementById("confirm").addEventListener("click", function (e) {
|
||||||
let d = clone(query);
|
var d = clone(query);
|
||||||
d.mint = document.getElementById('mint-url').value;
|
d.mint = document.getElementById('mint-url').value;
|
||||||
chrome.runtime.sendMessage({ type: 'confirm-reserve', detail: d }, (resp) => {
|
chrome.runtime.sendMessage({ type: 'confirm-reserve', detail: d }, function (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 =
|
||||||
`
|
"\n Oops, something went wrong.\n The bank responded with HTTP status code " + resp.status + ".\n Here is some more info:\n <pre>" + resp.text + "</pre>\n </div>";
|
||||||
Oops, something went wrong.
|
|
||||||
The bank responded with HTTP status code ${resp.status}.
|
|
||||||
Here is some more info:
|
|
||||||
<pre>${resp.text}</pre>
|
|
||||||
</div>`;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})(ConfirmCreateReserve || (ConfirmCreateReserve = {}));
|
})(ConfirmCreateReserve || (ConfirmCreateReserve = {}));
|
||||||
|
//# sourceMappingURL=confirm-create-reserve.js.map
|
@ -5,8 +5,8 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" href="popup.css" type="text/css">
|
<link rel="stylesheet" href="popup.css" type="text/css">
|
||||||
<script src="../lib/util.js" type="text/javascript"></script>
|
<script src="../lib/util.js" type="text/javascript"></script>
|
||||||
<script src="../lib/handlebars-v4.0.5.js"></script>
|
<script src="../lib/vendor/handlebars-v4.0.5.js" type="text/javascript"></script>
|
||||||
<script src="../lib/commonHelpers.js"></script>
|
<script src="../lib/commonHelpers.js" type="text/javascript"></script>
|
||||||
<script src="balance-overview.js" type="text/javascript"></script>
|
<script src="balance-overview.js" type="text/javascript"></script>
|
||||||
|
|
||||||
<script id="balance-template" type="text/x-handlebars-template">
|
<script id="balance-template" type="text/x-handlebars-template">
|
||||||
|
@ -14,30 +14,31 @@
|
|||||||
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";
|
"use strict";
|
||||||
document.addEventListener("DOMContentLoaded", (e) => {
|
document.addEventListener("DOMContentLoaded", function (e) {
|
||||||
console.log("content loaded");
|
console.log("content loaded");
|
||||||
chrome.runtime.sendMessage({ type: "balances" }, function (wallet) {
|
chrome.runtime.sendMessage({ type: "balances" }, function (wallet) {
|
||||||
let context = document.getElementById("balance-template").innerHTML;
|
var context = document.getElementById("balance-template").innerHTML;
|
||||||
let template = Handlebars.compile(context);
|
var template = Handlebars.compile(context);
|
||||||
document.getElementById("content").innerHTML = template(wallet);
|
document.getElementById("content").innerHTML = template(wallet);
|
||||||
console.log("got wallet", JSON.stringify(wallet));
|
console.log("got wallet", JSON.stringify(wallet));
|
||||||
let el = document.getElementById("link-kudos");
|
var el = document.getElementById("link-kudos");
|
||||||
if (el) {
|
if (el) {
|
||||||
el.onclick = (e) => {
|
el.onclick = function (e) {
|
||||||
let target = e.target;
|
var target = e.target;
|
||||||
chrome.tabs.create({
|
chrome.tabs.create({
|
||||||
"url": target.href
|
"url": target.href
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
document.getElementById("debug").addEventListener("click", (e) => {
|
document.getElementById("debug").addEventListener("click", function (e) {
|
||||||
chrome.tabs.create({
|
chrome.tabs.create({
|
||||||
"url": chrome.extension.getURL("pages/debug.html")
|
"url": chrome.extension.getURL("pages/debug.html")
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
document.getElementById("reset").addEventListener("click", (e) => {
|
document.getElementById("reset").addEventListener("click", function (e) {
|
||||||
chrome.runtime.sendMessage({ type: "reset" });
|
chrome.runtime.sendMessage({ type: "reset" });
|
||||||
window.close();
|
window.close();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
//# sourceMappingURL=balance-overview.js.map
|
55
extension/test/run_tests.js
Normal file
55
extension/test/run_tests.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Bridge between the mocha test runner / nodejs
|
||||||
|
* and the typescript / the wallet's module system.
|
||||||
|
*
|
||||||
|
* The test cases use better-assert as assert library
|
||||||
|
* with mocha's bdd UI.
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let assert = require("better-assert");
|
||||||
|
let vm = require("vm");
|
||||||
|
let fs = require("fs");
|
||||||
|
|
||||||
|
|
||||||
|
if ("function" !== typeof run) {
|
||||||
|
throw Error("test must be run with 'mocha --delay ...'");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("typeof require (here)", typeof require);
|
||||||
|
|
||||||
|
// We might need thins in the future ...
|
||||||
|
global.nodeRequire = function (modulePath) {
|
||||||
|
return require(modulePath);
|
||||||
|
};
|
||||||
|
|
||||||
|
global.require = global.nodeRequire;
|
||||||
|
|
||||||
|
let data = fs.readFileSync("lib/emscripten/libwrapper.js");
|
||||||
|
vm.runInThisContext(data);
|
||||||
|
|
||||||
|
// Do it here, since it breaks 'require''
|
||||||
|
let System = require("systemjs");
|
||||||
|
|
||||||
|
System.config({
|
||||||
|
defaultJSExtensions: true
|
||||||
|
});
|
||||||
|
|
||||||
|
let mod = System.newModule({Module: Module});
|
||||||
|
let modName = System.normalizeSync(__dirname + "/../lib/emscripten/emsc");
|
||||||
|
console.log("registering", modName);
|
||||||
|
System.set(modName, mod);
|
||||||
|
|
||||||
|
|
||||||
|
System.import("./test/tests/taler.js")
|
||||||
|
.then((t) => {
|
||||||
|
t.declareTests(assert, context, it);
|
||||||
|
run();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error("failed to load module", e.stack);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
10
extension/test/tests/taler.ts
Normal file
10
extension/test/tests/taler.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
import * as Emsc from '../../lib/wallet/emscriptif';
|
||||||
|
|
||||||
|
export function declareTests(assert, context, it) {
|
||||||
|
it("works!", function() {
|
||||||
|
let x = new Emsc.Amount({value: 42, fraction:42, currency: "EUR"});
|
||||||
|
let j = x.toJson();
|
||||||
|
assert("value" in j);
|
||||||
|
});
|
||||||
|
}
|
@ -1,23 +1,32 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es6",
|
"target": "es5",
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"experimentalDecorators": true
|
"experimentalDecorators": true,
|
||||||
|
"module": "system",
|
||||||
|
"noLib": true,
|
||||||
|
"sourceMap": true
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"background/wallet.ts",
|
"lib/refs.ts",
|
||||||
"background/emscriptif.ts",
|
"lib/wallet/wallet.ts",
|
||||||
"background/db.ts",
|
"lib/wallet/emscriptif.ts",
|
||||||
"background/query.ts",
|
"lib/wallet/db.ts",
|
||||||
"background/http.ts",
|
"lib/wallet/query.ts",
|
||||||
"background/checkable.ts",
|
"lib/wallet/http.ts",
|
||||||
"background/messaging.ts",
|
"lib/wallet/checkable.ts",
|
||||||
|
"lib/wallet/wxmessaging.ts",
|
||||||
|
"lib/wallet/types.ts",
|
||||||
"lib/util.ts",
|
"lib/util.ts",
|
||||||
|
"lib/commonHelpers.ts",
|
||||||
"lib/polyfill-react.ts",
|
"lib/polyfill-react.ts",
|
||||||
|
"lib/wallet/timerThread.ts",
|
||||||
"content_scripts/notify.ts",
|
"content_scripts/notify.ts",
|
||||||
|
"background/main.ts",
|
||||||
"popup/balance-overview.tsx",
|
"popup/balance-overview.tsx",
|
||||||
"popup/history.tsx",
|
"popup/history.tsx",
|
||||||
"pages/confirm-contract.tsx",
|
"pages/confirm-contract.tsx",
|
||||||
"pages/confirm-create-reserve.tsx"
|
"pages/confirm-create-reserve.tsx",
|
||||||
|
"test/tests/taler.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user