aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2015-12-17 22:56:24 +0100
committerFlorian Dold <florian.dold@gmail.com>2015-12-17 22:56:24 +0100
commit38c947d7712d77070ca521b4718032fb31c0f108 (patch)
treef460392f7f20fdf7ae01e1d3f57b524edd52932f
parent5f907c13fc76189ace1537af43903e7cd2c82c84 (diff)
Towards payment.
-rw-r--r--extension/background/db.js35
-rw-r--r--extension/background/db.ts89
-rw-r--r--extension/background/emscriptif.js215
-rw-r--r--extension/background/emscriptif.ts409
-rw-r--r--extension/background/libwrapper.js141
-rw-r--r--extension/background/wallet.js195
-rw-r--r--extension/background/wallet.ts409
-rw-r--r--extension/lib/util.js4
-rw-r--r--extension/lib/util.ts5
-rw-r--r--extension/pages/confirm-contract.html8
-rw-r--r--extension/pages/confirm-contract.js18
-rw-r--r--extension/pages/confirm-contract.tsx17
-rw-r--r--extension/pages/debug.html1
-rw-r--r--extension/popup/balance-overview.js15
-rw-r--r--extension/popup/balance-overview.tsx16
15 files changed, 1131 insertions, 446 deletions
diff --git a/extension/background/db.js b/extension/background/db.js
index b52ee457a..f6d81d9ac 100644
--- a/extension/background/db.js
+++ b/extension/background/db.js
@@ -1,5 +1,34 @@
+"use strict";
+const DB_NAME = "taler";
+const DB_VERSION = 1;
/**
- * Declarations and helpers for
- * things that are stored in the wallet's
- * database.
+ * 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 });
+ break;
+ }
+ };
+ });
+}
diff --git a/extension/background/db.ts b/extension/background/db.ts
new file mode 100644
index 000000000..12d944a83
--- /dev/null
+++ b/extension/background/db.ts
@@ -0,0 +1,89 @@
+"use strict";
+/**
+ * Declarations and helpers for
+ * things that are stored in the wallet's
+ * database.
+ */
+
+
+
+namespace Db {
+ export interface Mint {
+ baseUrl: string;
+ keys: Keys
+ }
+
+ export interface CoinWithDenom {
+ coin: Coin;
+ denom: Denomination;
+ }
+
+ export interface Keys {
+ denoms: { [key: string]: Denomination };
+ }
+
+ export interface Denomination {
+ value: AmountJson;
+ denom_pub: string;
+ fee_withdraw: AmountJson;
+ fee_deposit: AmountJson;
+ }
+
+ export interface PreCoin {
+ coinPub: string;
+ coinPriv: string;
+ reservePub: string;
+ denomPub: string;
+ blindingKey: string;
+ withdrawSig: string;
+ coinEv: string;
+ mintBaseUrl: string;
+ coinValue: AmountJson;
+ }
+
+ export interface Coin {
+ coinPub: string;
+ coinPriv: string;
+ denomPub: string;
+ denomSig: string;
+ currentAmount: AmountJson;
+ }
+
+
+}
+
+
+const DB_NAME = "taler";
+const DB_VERSION = 1;
+
+/**
+ * Return a promise that resolves
+ * to the taler wallet db.
+ */
+function openTalerDb(): Promise<IDBDatabase> {
+ 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: // DB does not exist yet
+ 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 });
+ break;
+ }
+ };
+ });
+}
diff --git a/extension/background/emscriptif.js b/extension/background/emscriptif.js
index 81580fbed..15eef7a3a 100644
--- a/extension/background/emscriptif.js
+++ b/extension/background/emscriptif.js
@@ -1,19 +1,19 @@
/*
- This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+ This file is part of TALER
+ Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
- 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 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.
+ 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, see <http://www.gnu.org/licenses/>
-*/
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
"use strict";
// Size of a native pointer.
const PTR_SIZE = 4;
@@ -30,6 +30,7 @@ var emsc = {
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']),
@@ -62,6 +63,7 @@ var emscAlloc = {
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) {
@@ -138,7 +140,7 @@ class SyncArena extends DefaultArena {
super();
let me = this;
this.timer = new Worker('background/timerThread.js');
- this.timer.onmessage = (e) => {
+ this.timer.onmessage = () => {
this.destroy();
};
//this.timer.postMessage({interval: 50});
@@ -164,6 +166,14 @@ class Amount extends ArenaObject {
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();
@@ -260,7 +270,9 @@ class PackedArenaObject extends ArenaObject {
}
}
class AmountNbo extends PackedArenaObject {
- size() { return 24; }
+ size() {
+ return 24;
+ }
}
class EddsaPrivateKey extends PackedArenaObject {
static create(a) {
@@ -268,30 +280,60 @@ class EddsaPrivateKey extends PackedArenaObject {
obj.nativePtr = emscAlloc.eddsa_key_create();
return obj;
}
- size() { return 32; }
+ size() {
+ return 32;
+ }
getPublicKey(a) {
let obj = new EddsaPublicKey(a);
obj.nativePtr = emscAlloc.eddsa_public_key_from_private(this.nativePtr);
return obj;
}
}
-class EddsaPublicKey extends PackedArenaObject {
- size() { return 32; }
+mixinStatic(EddsaPrivateKey, fromCrock);
+function fromCrock(s) {
+ let x = new this();
+ x.alloc();
+ x.loadCrock(s);
+ return x;
}
-class RsaBlindingKey extends ArenaObject {
- static create(len, a) {
- let o = new RsaBlindingKey(a);
- o.nativePtr = emscAlloc.rsa_blinding_key_create(len);
- return o;
+function mixin(obj, method, name) {
+ if (!name) {
+ name = method.name;
}
- static fromCrock(s, a) {
+ if (!name) {
+ throw Error("Mixin needs a name.");
+ }
+ console.log("mixing in", name, "into", obj.name);
+ obj.prototype[method.name] = method;
+}
+function mixinStatic(obj, method, name) {
+ if (!name) {
+ name = method.name;
+ }
+ if (!name) {
+ throw Error("Mixin needs a name.");
+ }
+ console.log("mixing in", name, "into", obj.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(emscAlloc.rsa_blinding_key_decode(buf.getNative(), buf.size()));
+ obj.setNative(decodeFn(buf.getNative(), buf.size()));
buf.destroy();
return obj;
}
- toCrock() {
+ 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, '*'));
@@ -300,12 +342,27 @@ class RsaBlindingKey extends ArenaObject {
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; }
+ size() {
+ return 64;
+ }
random(qualStr) {
let qual;
switch (qualStr) {
@@ -328,6 +385,7 @@ class HashCode extends PackedArenaObject {
emsc.hash_create_random(qual, this.nativePtr);
}
}
+mixinStatic(HashCode, fromCrock);
class ByteArray extends PackedArenaObject {
constructor(desiredSize, init, a) {
super(a);
@@ -339,7 +397,9 @@ class ByteArray extends PackedArenaObject {
}
this.allocatedSize = desiredSize;
}
- size() { return this.allocatedSize; }
+ size() {
+ return this.allocatedSize;
+ }
static fromString(s, a) {
let hstr = emscAlloc.malloc(s.length + 1);
Module.writeStringToMemory(s, hstr);
@@ -364,7 +424,9 @@ class EccSignaturePurpose extends PackedArenaObject {
this.nativePtr = emscAlloc.purpose_create(purpose, payload.nativePtr, payload.size());
this.payloadSize = payload.size();
}
- size() { return this.payloadSize + 8; }
+ size() {
+ return this.payloadSize + 8;
+ }
}
class SignatureStruct {
constructor(x) {
@@ -393,8 +455,7 @@ class SignatureStruct {
ptr += size;
}
let ba = new ByteArray(totalSize, buf, a);
- let x = new EccSignaturePurpose(this.purpose(), ba);
- return x;
+ return new EccSignaturePurpose(this.purpose(), ba);
}
set(name, value) {
let typemap = {};
@@ -414,32 +475,68 @@ class WithdrawRequestPS extends SignatureStruct {
constructor(w) {
super(w);
}
- purpose() { return SignaturePurpose.RESERVE_WITHDRAW; }
+ 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]];
+ ["h_coin_envelope", HashCode]
+ ];
}
}
-function encodeWith(obj, fn, arena) {
- let ptr = emscAlloc.malloc(PTR_SIZE);
- let len = fn(obj.getNative(), ptr);
- let res = new ByteArray(len, null, arena);
- res.setNative(Module.getValue(ptr, '*'));
- emsc.free(ptr);
- return res;
+class AbsoluteTimeNbo extends PackedArenaObject {
+ static fromTalerString(s) {
+ throw Error();
+ }
+ size() {
+ return 8;
+ }
}
-class RsaPublicKey extends ArenaObject {
- static fromCrock(s, a) {
- let obj = new RsaPublicKey(a);
- let buf = ByteArray.fromCrock(s);
- obj.nativePtr = emscAlloc.rsa_public_key_decode(buf.nativePtr, buf.size());
- buf.destroy();
- return obj;
+class UInt64 extends PackedArenaObject {
+ static fromNumber(n) {
+ throw Error();
+ }
+ 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();
}
@@ -447,38 +544,26 @@ class RsaPublicKey extends ArenaObject {
emsc.rsa_public_key_free(this.nativePtr);
this.nativePtr = 0;
}
- encode(arena) {
- let ptr = emscAlloc.malloc(PTR_SIZE);
- let len = emscAlloc.rsa_public_key_encode(this.nativePtr, ptr);
- let res = new ByteArray(len, Module.getValue(ptr, '*'), arena);
- emsc.free(ptr);
- return res;
- }
}
+mixinStatic(RsaPublicKey, makeFromCrock(emscAlloc.rsa_public_key_decode));
+mixin(RsaPublicKey, makeEncode(emscAlloc.rsa_public_key_encode));
class EddsaSignature extends PackedArenaObject {
- size() { return 64; }
+ size() {
+ return 64;
+ }
}
class RsaSignature extends ArenaObject {
- static fromCrock(s, a) {
- let obj = new this(a);
- let buf = ByteArray.fromCrock(s);
- obj.setNative(emscAlloc.rsa_signature_decode(buf.getNative(), buf.size()));
- buf.destroy();
- return obj;
- }
- encode(arena) {
- return encodeWith(this, emscAlloc.rsa_signature_encode);
- }
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);
- let res = new ByteArray(s, Module.getValue(ptr, '*'), arena);
- return res;
+ return new ByteArray(s, Module.getValue(ptr, '*'), arena);
}
function eddsaSign(purpose, priv, a) {
let sig = new EddsaSignature(a);
diff --git a/extension/background/emscriptif.ts b/extension/background/emscriptif.ts
index f21e60db4..ce6f351c0 100644
--- a/extension/background/emscriptif.ts
+++ b/extension/background/emscriptif.ts
@@ -1,23 +1,23 @@
/*
- This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+ This file is part of TALER
+ Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
- 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 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.
+ 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, see <http://www.gnu.org/licenses/>
-*/
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
"use strict";
-declare var Module : any;
+declare var Module: any;
// Size of a native pointer.
@@ -30,10 +30,18 @@ const GNUNET_SYSERR = -1;
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);
+ (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);
}
let getEmsc: EmscFunGen = (...args) => Module.cwrap.apply(null, args);
@@ -58,15 +66,18 @@ var emsc = {
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']),
+ 'void',
+ ['number', 'number']),
amount_ntoh: getEmsc('TALER_amount_ntoh',
- 'void',
- ['number', 'number']),
+ 'void',
+ ['number', 'number']),
hash: getEmsc('GNUNET_CRYPTO_hash',
'void',
['number', 'number', 'number']),
@@ -77,8 +88,8 @@ var emsc = {
'void',
['number']),
rsa_signature_free: getEmsc('GNUNET_CRYPTO_rsa_signature_free',
- 'void',
- ['number']),
+ 'void',
+ ['number']),
string_to_data: getEmsc('GNUNET_STRINGS_string_to_data',
'number',
['number', 'number', 'number', 'number']),
@@ -89,8 +100,8 @@ var emsc = {
'void',
['number', 'number']),
rsa_blinding_key_destroy: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_free',
- 'void',
- ['number']),
+ 'void',
+ ['number']),
};
var emscAlloc = {
@@ -99,9 +110,10 @@ var emscAlloc = {
['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']),
+ 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']),
@@ -112,35 +124,36 @@ var emscAlloc = {
'number',
['number', 'number', 'number', 'number']),
rsa_blinding_key_create: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_create',
- 'number',
- ['number']),
+ 'number',
+ ['number']),
rsa_blinding_key_encode: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_encode',
- 'number',
- ['number', 'number']),
+ 'number',
+ ['number', 'number']),
rsa_signature_encode: getEmsc('GNUNET_CRYPTO_rsa_signature_encode',
- 'number',
- ['number', 'number']),
+ 'number',
+ ['number', 'number']),
rsa_blinding_key_decode: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_decode',
- 'number',
- ['number', 'number']),
+ 'number',
+ ['number', 'number']),
rsa_public_key_decode: getEmsc('GNUNET_CRYPTO_rsa_public_key_decode',
- 'number',
- ['number', 'number']),
+ 'number',
+ ['number', 'number']),
rsa_signature_decode: getEmsc('GNUNET_CRYPTO_rsa_signature_decode',
- 'number',
- ['number', 'number']),
+ 'number',
+ ['number', 'number']),
rsa_public_key_encode: getEmsc('GNUNET_CRYPTO_rsa_public_key_encode',
- 'number',
- ['number', 'number']),
+ 'number',
+ ['number', 'number']),
rsa_unblind: getEmsc('GNUNET_CRYPTO_rsa_unblind',
- 'number',
- ['number', 'number', 'number']),
+ 'number',
+ ['number', 'number', 'number']),
malloc: (size: number) => Module._malloc(size),
};
enum SignaturePurpose {
- RESERVE_WITHDRAW = 1200
+ RESERVE_WITHDRAW = 1200,
+ WALLET_COIN_DEPOSIT = 1201,
}
enum RandomQuality {
@@ -153,6 +166,7 @@ enum RandomQuality {
abstract class ArenaObject {
private _nativePtr: number;
arena: Arena;
+
abstract destroy(): void;
constructor(arena?: Arena) {
@@ -172,7 +186,7 @@ abstract class ArenaObject {
// of native wrappers, but we never want to
// pass 'undefined' to emscripten.
if (this._nativePtr === undefined) {
- throw Error("Native pointer not initialized");
+ throw Error("Native pointer not initialized");
}
return this._nativePtr;
}
@@ -198,11 +212,11 @@ abstract class ArenaObject {
this._nativePtr = n;
}
- set nativePtr (v) {
+ set nativePtr(v) {
this.setNative(v);
}
- get nativePtr () {
+ get nativePtr() {
return this.getNative();
}
@@ -215,6 +229,7 @@ interface Arena {
class DefaultArena implements Arena {
heap: Array<ArenaObject>;
+
constructor() {
this.heap = [];
}
@@ -238,31 +253,35 @@ class DefaultArena implements Arena {
*/
class SyncArena extends DefaultArena {
timer: Worker;
+
constructor() {
super();
let me = this;
this.timer = new Worker('background/timerThread.js');
- this.timer.onmessage = (e) => {
+ this.timer.onmessage = () => {
this.destroy();
};
//this.timer.postMessage({interval: 50});
}
+
destroy() {
super.destroy();
}
}
-
let arenaStack: Arena[] = [];
arenaStack.push(new SyncArena());
class Amount extends ArenaObject {
- constructor(args?: any, arena?: Arena) {
+ constructor(args?: AmountJson, arena?: Arena) {
super(arena);
if (args) {
- this.nativePtr = emscAlloc.get_amount(args.value, 0, args.fraction, args.currency);
+ this.nativePtr = emscAlloc.get_amount(args.value,
+ 0,
+ args.fraction,
+ args.currency);
} else {
this.nativePtr = emscAlloc.get_amount(0, 0, 0, "");
}
@@ -274,6 +293,17 @@ class Amount extends ArenaObject {
}
}
+
+ static getZero(currency: string, a?: Arena) {
+ 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?: Arena): AmountNbo {
let x = new AmountNbo(a);
x.alloc();
@@ -362,7 +392,10 @@ abstract class PackedArenaObject extends ArenaObject {
// 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());
+ let res = emsc.string_to_data(buf.nativePtr,
+ s.length,
+ this.nativePtr,
+ this.size());
buf.destroy();
if (res < 1) {
throw {error: "wrong encoding"};
@@ -390,7 +423,9 @@ abstract class PackedArenaObject extends ArenaObject {
class AmountNbo extends PackedArenaObject {
- size() { return 24; }
+ size() {
+ return 24;
+ }
}
@@ -401,37 +436,76 @@ class EddsaPrivateKey extends PackedArenaObject {
return obj;
}
- size() { return 32; }
+ size() {
+ return 32;
+ }
getPublicKey(a?: Arena): EddsaPublicKey {
let obj = new EddsaPublicKey(a);
obj.nativePtr = emscAlloc.eddsa_public_key_from_private(this.nativePtr);
return obj;
}
+
+ static fromCrock: (string) => EddsaPrivateKey;
}
+mixinStatic(EddsaPrivateKey, fromCrock);
-class EddsaPublicKey extends PackedArenaObject {
- size() { return 32; }
+function fromCrock(s: string) {
+ let x = new this();
+ x.alloc();
+ x.loadCrock(s);
+ return x;
+}
+
+
+function mixin(obj, method, name?: string) {
+ if (!name) {
+ name = method.name;
+ }
+ if (!name) {
+ throw Error("Mixin needs a name.");
+ }
+ console.log("mixing in", name, "into", obj.name);
+ obj.prototype[method.name] = method;
}
+function mixinStatic(obj, method, name?: string) {
+ if (!name) {
+ name = method.name;
+ }
+ if (!name) {
+ throw Error("Mixin needs a name.");
+ }
+ console.log("mixing in", name, "into", obj.name);
+ obj[method.name] = method;
+}
-class RsaBlindingKey extends ArenaObject {
- static create(len: number, a?: Arena) {
- let o = new RsaBlindingKey(a);
- o.nativePtr = emscAlloc.rsa_blinding_key_create(len);
- return o;
+
+class EddsaPublicKey extends PackedArenaObject {
+ size() {
+ return 32;
}
- static fromCrock(s: string, a?: Arena): RsaBlindingKey {
+ static fromCrock: (s: string) => EddsaPublicKey;
+}
+mixinStatic(EddsaPublicKey, fromCrock);
+
+function makeFromCrock(decodeFn: (p: number, s: number) => number) {
+ function fromCrock(s: string, a?: Arena) {
let obj = new this(a);
let buf = ByteArray.fromCrock(s);
- obj.setNative(emscAlloc.rsa_blinding_key_decode(buf.getNative(), buf.size()));
+ obj.setNative(decodeFn(buf.getNative(),
+ buf.size()));
buf.destroy();
return obj;
}
- toCrock(): string {
+ return fromCrock;
+}
+
+function makeToCrock(encodeFn: (po: number, ps: number) => number): () => string {
+ 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, '*'));
@@ -440,15 +514,32 @@ class RsaBlindingKey extends ArenaObject {
res.destroy();
return s;
}
+ return toCrock;
+}
+
+class RsaBlindingKey extends ArenaObject {
+ static create(len: number, a?: Arena) {
+ let o = new RsaBlindingKey(a);
+ o.nativePtr = emscAlloc.rsa_blinding_key_create(len);
+ return o;
+ }
+
+ static fromCrock: (s: string, a?: Arena) => RsaBlindingKey;
+ toCrock = makeToCrock(emscAlloc.rsa_blinding_key_encode);
destroy() {
// TODO
}
}
+mixinStatic(RsaBlindingKey, makeFromCrock(emscAlloc.rsa_blinding_key_decode));
class HashCode extends PackedArenaObject {
- size() { return 64; }
+ size() {
+ return 64;
+ }
+
+ static fromCrock: (s: string) => HashCode;
random(qualStr: string) {
let qual: RandomQuality;
@@ -472,11 +563,15 @@ class HashCode extends PackedArenaObject {
emsc.hash_create_random(qual, this.nativePtr);
}
}
+mixinStatic(HashCode, fromCrock);
class ByteArray extends PackedArenaObject {
private allocatedSize: number;
- size() { return this.allocatedSize; }
+
+ size() {
+ return this.allocatedSize;
+ }
constructor(desiredSize: number, init: number, a?: Arena) {
super(a);
@@ -510,11 +605,19 @@ class ByteArray extends PackedArenaObject {
class EccSignaturePurpose extends PackedArenaObject {
- size() { return this.payloadSize + 8; }
+ size() {
+ return this.payloadSize + 8;
+ }
+
payloadSize: number;
- constructor(purpose: SignaturePurpose, payload: PackedArenaObject, a?: Arena) {
+
+ constructor(purpose: SignaturePurpose,
+ payload: PackedArenaObject,
+ a?: Arena) {
super(a);
- this.nativePtr = emscAlloc.purpose_create(purpose, payload.nativePtr, payload.size());
+ this.nativePtr = emscAlloc.purpose_create(purpose,
+ payload.nativePtr,
+ payload.size());
this.payloadSize = payload.size();
}
}
@@ -522,7 +625,9 @@ class EccSignaturePurpose extends PackedArenaObject {
abstract class SignatureStruct {
abstract fieldTypes(): Array<any>;
+
abstract purpose(): SignaturePurpose;
+
private members: any = {};
constructor(x: { [name: string]: any }) {
@@ -552,12 +657,11 @@ abstract class SignatureStruct {
ptr += size;
}
let ba = new ByteArray(totalSize, buf, a);
- let x = new EccSignaturePurpose(this.purpose(), ba);
- return x;
+ return new EccSignaturePurpose(this.purpose(), ba);
}
protected set(name: string, value: PackedArenaObject) {
- let typemap: any = {}
+ let typemap: any = {};
for (let f of this.fieldTypes()) {
typemap[f[0]] = f[1];
}
@@ -586,98 +690,156 @@ class WithdrawRequestPS extends SignatureStruct {
constructor(w: WithdrawRequestPS_Args) {
super(w);
}
- purpose() { return SignaturePurpose.RESERVE_WITHDRAW; }
+
+ 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]];
+ ["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: string): AbsoluteTimeNbo {
+ throw Error();
+ }
-function encodeWith(obj, fn, arena?: Arena) {
- let ptr = emscAlloc.malloc(PTR_SIZE);
- let len = fn(obj.getNative(), ptr);
- let res = new ByteArray(len, null, arena);
- res.setNative(Module.getValue(ptr, '*'));
- emsc.free(ptr);
- return res;
+ size() {
+ return 8;
+ }
}
-class RsaPublicKey extends ArenaObject {
- static fromCrock(s: string, a?: Arena): RsaPublicKey {
- let obj = new RsaPublicKey(a);
- let buf = ByteArray.fromCrock(s);
- obj.nativePtr = emscAlloc.rsa_public_key_decode(buf.nativePtr, buf.size());
- buf.destroy();
- return obj;
+class UInt64 extends PackedArenaObject {
+ static fromNumber(n: number): UInt64 {
+ throw Error();
}
- toCrock() {
- return this.encode().toCrock();
+ size() {
+ return 8;
}
+}
- destroy() {
- emsc.rsa_public_key_free(this.nativePtr);
- this.nativePtr = 0;
+
+// It's redundant, but more type safe.
+interface DepositRequestPS_Args {
+ 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;
+}
+
+
+class DepositRequestPS extends SignatureStruct {
+ constructor(w: DepositRequestPS_Args) {
+ super(w);
+ }
+
+ purpose() {
+ return SignaturePurpose.WALLET_COIN_DEPOSIT;
}
- encode(arena?: Arena): ByteArray {
+ 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],
+ ];
+ }
+}
+
+
+interface Encodeable {
+ encode(arena?: Arena): ByteArray;
+}
+
+function makeEncode(encodeFn) {
+ function encode(arena?: Arena) {
let ptr = emscAlloc.malloc(PTR_SIZE);
- let len = emscAlloc.rsa_public_key_encode(this.nativePtr, ptr);
- let res = new ByteArray(len, Module.getValue(ptr, '*'), arena);
+ 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 implements Encodeable {
+ static fromCrock: (s: string, a?: Arena) => RsaPublicKey;
+
+ toCrock() {
+ return this.encode().toCrock();
+ }
+ destroy() {
+ emsc.rsa_public_key_free(this.nativePtr);
+ this.nativePtr = 0;
+ }
+
+ encode: (arena?: Arena) => ByteArray;
}
+mixinStatic(RsaPublicKey, makeFromCrock(emscAlloc.rsa_public_key_decode));
+mixin(RsaPublicKey, makeEncode(emscAlloc.rsa_public_key_encode));
class EddsaSignature extends PackedArenaObject {
- size() { return 64; }
+ size() {
+ return 64;
+ }
}
-class RsaSignature extends ArenaObject {
- static fromCrock(s: string, a?: Arena): RsaSignature {
- let obj = new this(a);
- let buf = ByteArray.fromCrock(s);
- obj.setNative(emscAlloc.rsa_signature_decode(buf.getNative(), buf.size()));
- buf.destroy();
- return obj;
- }
+class RsaSignature extends ArenaObject implements Encodeable{
+ static fromCrock: (s: string, a?: Arena) => RsaSignature;
- encode(arena?: Arena): ByteArray {
- return encodeWith(this, emscAlloc.rsa_signature_encode);
- }
+ encode: (arena?: Arena) => ByteArray;
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: HashCode,
- blindingKey: RsaBlindingKey,
+ blindingKey: RsaBlindingKey,
pkey: RsaPublicKey,
- arena?: Arena): ByteArray
-{
+ arena?: Arena): ByteArray {
let ptr = emscAlloc.malloc(PTR_SIZE);
- let s = emscAlloc.rsa_blind(hashCode.nativePtr, blindingKey.nativePtr, pkey.nativePtr, ptr);
- let res = new ByteArray(s, Module.getValue(ptr, '*'), arena);
- return res;
+ let s = emscAlloc.rsa_blind(hashCode.nativePtr,
+ blindingKey.nativePtr,
+ pkey.nativePtr,
+ ptr);
+ return new ByteArray(s, Module.getValue(ptr, '*'), arena);
}
function eddsaSign(purpose: EccSignaturePurpose,
priv: EddsaPrivateKey,
- a?: Arena): EddsaSignature
-{
+ a?: Arena): EddsaSignature {
let sig = new EddsaSignature(a);
sig.alloc();
let res = emsc.eddsa_sign(priv.nativePtr, purpose.nativePtr, sig.nativePtr);
@@ -687,13 +849,14 @@ function eddsaSign(purpose: EccSignaturePurpose,
return sig;
}
+
function rsaUnblind(sig: RsaSignature,
bk: RsaBlindingKey,
pk: RsaPublicKey,
a?: Arena): RsaSignature {
let x = new RsaSignature(a);
- x.nativePtr = emscAlloc.rsa_unblind(sig.nativePtr, bk.nativePtr, pk.nativePtr);
+ x.nativePtr = emscAlloc.rsa_unblind(sig.nativePtr,
+ bk.nativePtr,
+ pk.nativePtr);
return x;
}
-
-
diff --git a/extension/background/libwrapper.js b/extension/background/libwrapper.js
index 46d198372..791359a25 100644
--- a/extension/background/libwrapper.js
+++ b/extension/background/libwrapper.js
@@ -8890,85 +8890,73 @@ function _TALER_WR_multiply_amount($a,$factor) {
function _TALER_WR_multiply_amounts($a,$b) {
$a = $a|0;
$b = $b|0;
- var $0 = 0.0, $1 = 0, $10 = 0, $11 = 0, $12 = 0, $13 = 0.0, $14 = 0.0, $15 = 0, $16 = 0, $17 = 0, $18 = 0, $19 = 0, $2 = 0, $20 = 0, $21 = 0, $22 = 0.0, $23 = 0.0, $24 = 0.0, $25 = 0, $26 = 0;
- var $27 = 0, $28 = 0, $29 = 0, $3 = 0, $30 = 0, $31 = 0, $32 = 0.0, $33 = 0.0, $34 = 0.0, $35 = 0.0, $36 = 0.0, $37 = 0.0, $38 = 0.0, $39 = 0, $4 = 0, $40 = 0.0, $41 = 0, $42 = 0.0, $43 = 0.0, $44 = 0.0;
- var $45 = 0, $46 = 0.0, $47 = 0.0, $48 = 0.0, $49 = 0, $5 = 0, $50 = 0.0, $51 = 0.0, $6 = 0, $7 = 0, $8 = 0.0, $9 = 0.0, $ad = 0.0, $bd = 0.0, $or$cond = 0, $ret = 0.0, label = 0, sp = 0;
+ var $0 = 0.0, $1 = 0, $10 = 0, $11 = 0, $12 = 0.0, $13 = 0.0, $14 = 0, $15 = 0, $16 = 0, $17 = 0.0, $18 = 0.0, $19 = 0, $2 = 0, $20 = 0, $21 = 0, $22 = 0, $23 = 0, $24 = 0, $25 = 0, $26 = 0.0;
+ var $27 = 0.0, $28 = 0.0, $29 = 0, $3 = 0, $30 = 0, $31 = 0, $32 = 0, $33 = 0, $34 = 0, $35 = 0, $36 = 0.0, $37 = 0.0, $38 = 0.0, $39 = 0.0, $4 = 0, $40 = 0.0, $41 = 0.0, $42 = 0.0, $43 = 0.0, $5 = 0;
+ var $6 = 0, $7 = 0, $8 = 0, $9 = 0, $ad = 0.0, $bd = 0.0, $ret = 0.0, label = 0, sp = 0;
sp = STACKTOP;
STACKTOP = STACKTOP + 48|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
$1 = $a;
$2 = $b;
$3 = $1;
- (_TALER_amount_normalize($3)|0);
- $4 = $2;
- (_TALER_amount_normalize($4)|0);
- $5 = $1;
- $6 = ((($5)) + 8|0);
- $7 = HEAP32[$6>>2]|0;
- $8 = (+($7>>>0));
- $9 = $8 / 1.0E+6;
- $ad = $9;
- $10 = $2;
- $11 = ((($10)) + 8|0);
- $12 = HEAP32[$11>>2]|0;
- $13 = (+($12>>>0));
- $14 = $13 / 1.0E+6;
- $bd = $14;
- $15 = $1;
- $16 = $15;
- $17 = $16;
- $18 = HEAP32[$17>>2]|0;
- $19 = (($16) + 4)|0;
- $20 = $19;
- $21 = HEAP32[$20>>2]|0;
- $22 = (+($18>>>0)) + (4294967296.0*(+($21>>>0)));
- $23 = $ad;
- $24 = $23 + $22;
- $ad = $24;
- $25 = $2;
- $26 = $25;
- $27 = $26;
- $28 = HEAP32[$27>>2]|0;
- $29 = (($26) + 4)|0;
- $30 = $29;
- $31 = HEAP32[$30>>2]|0;
- $32 = (+($28>>>0)) + (4294967296.0*(+($31>>>0)));
- $33 = $bd;
- $34 = $33 + $32;
- $bd = $34;
- $35 = $ad;
- $36 = $bd;
- $37 = $35 * $36;
- $ret = $37;
- $38 = $ad;
- $39 = $38 < 1.0;
- $40 = $bd;
- $41 = $40 < 1.0;
- $or$cond = $39 | $41;
- $42 = $ret;
- $43 = $ad;
- $44 = $bd;
- $45 = $43 > $44;
- $46 = $ad;
- $47 = $bd;
- $48 = $45 ? $46 : $47;
- $49 = $42 < $48;
- if ($or$cond) {
- if (!($49)) {
- $0 = -1.0;
- $51 = $0;
- STACKTOP = sp;return (+$51);
- }
+ $4 = (_TALER_amount_normalize($3)|0);
+ $5 = (-1)==($4|0);
+ if ($5) {
+ $0 = -1.0;
+ $43 = $0;
+ STACKTOP = sp;return (+$43);
+ }
+ $6 = $2;
+ $7 = (_TALER_amount_normalize($6)|0);
+ $8 = (-1)==($7|0);
+ if ($8) {
+ $0 = -1.0;
+ $43 = $0;
+ STACKTOP = sp;return (+$43);
} else {
- if ($49) {
- $0 = -1.0;
- $51 = $0;
- STACKTOP = sp;return (+$51);
- }
+ $9 = $1;
+ $10 = ((($9)) + 8|0);
+ $11 = HEAP32[$10>>2]|0;
+ $12 = (+($11>>>0));
+ $13 = $12 / 1.0E+6;
+ $ad = $13;
+ $14 = $2;
+ $15 = ((($14)) + 8|0);
+ $16 = HEAP32[$15>>2]|0;
+ $17 = (+($16>>>0));
+ $18 = $17 / 1.0E+6;
+ $bd = $18;
+ $19 = $1;
+ $20 = $19;
+ $21 = $20;
+ $22 = HEAP32[$21>>2]|0;
+ $23 = (($20) + 4)|0;
+ $24 = $23;
+ $25 = HEAP32[$24>>2]|0;
+ $26 = (+($22>>>0)) + (4294967296.0*(+($25>>>0)));
+ $27 = $ad;
+ $28 = $27 + $26;
+ $ad = $28;
+ $29 = $2;
+ $30 = $29;
+ $31 = $30;
+ $32 = HEAP32[$31>>2]|0;
+ $33 = (($30) + 4)|0;
+ $34 = $33;
+ $35 = HEAP32[$34>>2]|0;
+ $36 = (+($32>>>0)) + (4294967296.0*(+($35>>>0)));
+ $37 = $bd;
+ $38 = $37 + $36;
+ $bd = $38;
+ $39 = $ad;
+ $40 = $bd;
+ $41 = $39 * $40;
+ $ret = $41;
+ $42 = $ret;
+ $0 = $42;
+ $43 = $0;
+ STACKTOP = sp;return (+$43);
}
- $50 = $ret;
- $0 = $50;
- $51 = $0;
- STACKTOP = sp;return (+$51);
+ return +(0.0);
}
function _GNUNET_xmalloc_($size,$filename,$linenumber) {
$size = $size|0;
@@ -145293,7 +145281,7 @@ var FUNCTION_TABLE_viiii = [b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,
,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,_reporter,b10,b10
,b10,b10,b10,b10,b10];
- return { _WRALL_make_purpose: _WRALL_make_purpose, _GNUNET_CRYPTO_rsa_blinding_key_encode: _GNUNET_CRYPTO_rsa_blinding_key_encode, _bitshift64Lshr: _bitshift64Lshr, _bitshift64Ashr: _bitshift64Ashr, _GNUNET_CRYPTO_eddsa_key_create: _GNUNET_CRYPTO_eddsa_key_create, _memcpy: _memcpy, _TALER_WR_GNUNET_free: _TALER_WR_GNUNET_free, _TALER_WRALL_amount_add: _TALER_WRALL_amount_add, _GNUNET_CRYPTO_rsa_private_key_decode: _GNUNET_CRYPTO_rsa_private_key_decode, _TALER_WR_multiply_amount: _TALER_WR_multiply_amount, _GNUNET_CRYPTO_rsa_blinding_key_decode: _GNUNET_CRYPTO_rsa_blinding_key_decode, _GNUNET_CRYPTO_ecc_ecdh: _GNUNET_CRYPTO_ecc_ecdh, _TALER_amount_hton: _TALER_amount_hton, _TALER_WR_verify_sign_key_enc: _TALER_WR_verify_sign_key_enc, _free: _free, _TALER_WRALL_sign_deposit_permission: _TALER_WRALL_sign_deposit_permission, _TALER_WR_verify_denoms: _TALER_WR_verify_denoms, _GNUNET_CRYPTO_rsa_blinding_key_create: _GNUNET_CRYPTO_rsa_blinding_key_create, _TALER_WR_verify_sign_key: _TALER_WR_verify_sign_key, _TALER_WRALL_rsa_public_key_hash: _TALER_WRALL_rsa_public_key_hash, _TALER_WRALL_gen_key_from_blob: _TALER_WRALL_gen_key_from_blob, _GNUNET_CRYPTO_rsa_private_key_get_public: _GNUNET_CRYPTO_rsa_private_key_get_public, _TALER_WRALL_rsa_public_key_decode_from_string: _TALER_WRALL_rsa_public_key_decode_from_string, _GNUNET_CRYPTO_symmetric_encrypt: _GNUNET_CRYPTO_symmetric_encrypt, _TALER_WR_get_fraction: _TALER_WR_get_fraction, _TALER_WR_verify_denoms_enc: _TALER_WR_verify_denoms_enc, _TALER_amount_cmp: _TALER_amount_cmp, _TALER_WRALL_ecdhe_public_key_from_private_key: _TALER_WRALL_ecdhe_public_key_from_private_key, _llvm_cttz_i32: _llvm_cttz_i32, _TALER_WRALL_eddsa_private_key_from_string: _TALER_WRALL_eddsa_private_key_from_string, _TALER_WRALL_gen_init_vector: _TALER_WRALL_gen_init_vector, _TALER_amount_ntoh: _TALER_amount_ntoh, _WR_verify_test: _WR_verify_test, _GNUNET_CRYPTO_rsa_public_key_free: _GNUNET_CRYPTO_rsa_public_key_free, _GNUNET_CRYPTO_hkdf: _GNUNET_CRYPTO_hkdf, _GNUNET_CRYPTO_eddsa_key_get_public: _GNUNET_CRYPTO_eddsa_key_get_public, _llvm_bswap_i32: _llvm_bswap_i32, _GNUNET_CRYPTO_rsa_private_key_create: _GNUNET_CRYPTO_rsa_private_key_create, _GNUNET_STRINGS_data_to_string_alloc: _GNUNET_STRINGS_data_to_string_alloc, _TALER_WRALL_sign_test: _TALER_WRALL_sign_test, _TALER_WR_verify_confirmation: _TALER_WR_verify_confirmation, _GNUNET_CRYPTO_rsa_public_key_decode: _GNUNET_CRYPTO_rsa_public_key_decode, _GNUNET_CRYPTO_rsa_blinding_key_free: _GNUNET_CRYPTO_rsa_blinding_key_free, _GNUNET_CRYPTO_rsa_signature_encode: _GNUNET_CRYPTO_rsa_signature_encode, _GNUNET_CRYPTO_rsa_verify: _GNUNET_CRYPTO_rsa_verify, _TALER_WR_eddsa_verify: _TALER_WR_eddsa_verify, _GNUNET_STRINGS_string_to_data: _GNUNET_STRINGS_string_to_data, _TALER_WRALL_gen_symmetric_key: _TALER_WRALL_gen_symmetric_key, _TALER_WRALL_ecc_ecdh: _TALER_WRALL_ecc_ecdh, _memset: _memset, _GNUNET_CRYPTO_rsa_unblind: _GNUNET_CRYPTO_rsa_unblind, _TALER_WR_get_currency: _TALER_WR_get_currency, _DEBUG_WR_get_purpose: _DEBUG_WR_get_purpose, _TALER_WRALL_get_amount: _TALER_WRALL_get_amount, _GNUNET_CRYPTO_rsa_private_key_encode: _GNUNET_CRYPTO_rsa_private_key_encode, _GNUNET_CRYPTO_symmetric_decrypt: _GNUNET_CRYPTO_symmetric_decrypt, _i64Subtract: _i64Subtract, _TALER_WR_get_value: _TALER_WR_get_value, _GNUNET_CRYPTO_rsa_signature_free: _GNUNET_CRYPTO_rsa_signature_free, _TALER_WRALL_eddsa_public_key_from_priv_string: _TALER_WRALL_eddsa_public_key_from_priv_string, _GNUNET_CRYPTO_rsa_blind: _GNUNET_CRYPTO_rsa_blind, _TALER_WR_verify_denom_enc: _TALER_WR_verify_denom_enc, _malloc: _malloc, _TALER_WR_hello_world: _TALER_WR_hello_world, _TALER_WRALL_make_withdraw_bundle: _TALER_WRALL_make_withdraw_bundle, _GNUNET_CRYPTO_rsa_signature_decode: _GNUNET_CRYPTO_rsa_signature_decode, _GNUNET_CRYPTO_rsa_sign: _GNUNET_CRYPTO_rsa_sign, _GNUNET_CRYPTO_ecdhe_key_create: _GNUNET_CRYPTO_ecdhe_key_create, _TALER_WRALL_get_encoding_from_rsa_signature: _TALER_WRALL_get_encoding_from_rsa_signature, _TALER_WRALL_hash: _TALER_WRALL_hash, _TALER_amount_normalize: _TALER_amount_normalize, _TALER_WRALL_sign_contract: _TALER_WRALL_sign_contract, _bitshift64Shl: _bitshift64Shl, _GNUNET_CRYPTO_rsa_private_key_free: _GNUNET_CRYPTO_rsa_private_key_free, _fflush: _fflush, _GNUNET_CRYPTO_hash_create_random: _GNUNET_CRYPTO_hash_create_random, _TALER_WRALL_eddsa_public_key_from_private: _TALER_WRALL_eddsa_public_key_from_private, _TALER_WR_multiply_amounts: _TALER_WR_multiply_amounts, _TALER_amount_add: _TALER_amount_add, _GNUNET_CRYPTO_ecdhe_key_get_public: _GNUNET_CRYPTO_ecdhe_key_get_public, _TALER_amount_subtract: _TALER_amount_subtract, _i64Add: _i64Add, _TALER_WRALL_purpose_create: _TALER_WRALL_purpose_create, _GNUNET_CRYPTO_eddsa_sign: _GNUNET_CRYPTO_eddsa_sign, _TALER_WR_verify_denom: _TALER_WR_verify_denom, _TALER_WRALL_get_current_time: _TALER_WRALL_get_current_time, ___errno_location: ___errno_location, _TALER_WR_get_fancy_time: _TALER_WR_get_fancy_time, _TALER_WRALL_make_eddsa_signature: _TALER_WRALL_make_eddsa_signature, _memmove: _memmove, _DEBUG_WR_dump_amount: _DEBUG_WR_dump_amount, _GNUNET_CRYPTO_rsa_public_key_encode: _GNUNET_CRYPTO_rsa_public_key_encode, _GNUNET_CRYPTO_hash: _GNUNET_CRYPTO_hash, _GNUNET_util_cl_init: _GNUNET_util_cl_init, _GNUNET_CRYPTO_random_init: _GNUNET_CRYPTO_random_init, _gpg_err_init: _gpg_err_init, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, establishStackSpace: establishStackSpace, setThrew: setThrew, setTempRet0: setTempRet0, getTempRet0: getTempRet0, dynCall_iiii: dynCall_iiii, dynCall_viiiii: dynCall_viiiii, dynCall_vi: dynCall_vi, dynCall_vii: dynCall_vii, dynCall_ii: dynCall_ii, dynCall_viii: dynCall_viii, dynCall_v: dynCall_v, dynCall_iiiii: dynCall_iiiii, dynCall_viiiiii: dynCall_viiiiii, dynCall_iii: dynCall_iii, dynCall_viiii: dynCall_viiii };
+ return { _WRALL_make_purpose: _WRALL_make_purpose, _GNUNET_CRYPTO_rsa_blinding_key_encode: _GNUNET_CRYPTO_rsa_blinding_key_encode, _bitshift64Lshr: _bitshift64Lshr, _bitshift64Ashr: _bitshift64Ashr, _GNUNET_CRYPTO_eddsa_key_create: _GNUNET_CRYPTO_eddsa_key_create, _memcpy: _memcpy, _TALER_WR_GNUNET_free: _TALER_WR_GNUNET_free, _TALER_WRALL_amount_add: _TALER_WRALL_amount_add, _GNUNET_CRYPTO_rsa_private_key_decode: _GNUNET_CRYPTO_rsa_private_key_decode, _TALER_WR_multiply_amount: _TALER_WR_multiply_amount, _GNUNET_CRYPTO_rsa_blinding_key_decode: _GNUNET_CRYPTO_rsa_blinding_key_decode, _GNUNET_CRYPTO_ecc_ecdh: _GNUNET_CRYPTO_ecc_ecdh, _TALER_amount_hton: _TALER_amount_hton, _TALER_WR_verify_sign_key_enc: _TALER_WR_verify_sign_key_enc, _free: _free, _TALER_WRALL_sign_deposit_permission: _TALER_WRALL_sign_deposit_permission, _TALER_WR_verify_denoms: _TALER_WR_verify_denoms, _GNUNET_CRYPTO_rsa_blinding_key_create: _GNUNET_CRYPTO_rsa_blinding_key_create, _TALER_WR_verify_sign_key: _TALER_WR_verify_sign_key, _TALER_WRALL_rsa_public_key_hash: _TALER_WRALL_rsa_public_key_hash, _TALER_WRALL_gen_key_from_blob: _TALER_WRALL_gen_key_from_blob, _GNUNET_CRYPTO_rsa_private_key_get_public: _GNUNET_CRYPTO_rsa_private_key_get_public, _TALER_WRALL_rsa_public_key_decode_from_string: _TALER_WRALL_rsa_public_key_decode_from_string, _GNUNET_CRYPTO_symmetric_encrypt: _GNUNET_CRYPTO_symmetric_encrypt, _TALER_WR_get_fraction: _TALER_WR_get_fraction, _TALER_WR_verify_denoms_enc: _TALER_WR_verify_denoms_enc, _TALER_amount_cmp: _TALER_amount_cmp, _TALER_WRALL_ecdhe_public_key_from_private_key: _TALER_WRALL_ecdhe_public_key_from_private_key, _llvm_cttz_i32: _llvm_cttz_i32, _TALER_WRALL_eddsa_private_key_from_string: _TALER_WRALL_eddsa_private_key_from_string, _TALER_WRALL_gen_init_vector: _TALER_WRALL_gen_init_vector, _TALER_amount_ntoh: _TALER_amount_ntoh, _WR_verify_test: _WR_verify_test, _GNUNET_CRYPTO_rsa_public_key_free: _GNUNET_CRYPTO_rsa_public_key_free, _GNUNET_CRYPTO_hkdf: _GNUNET_CRYPTO_hkdf, _GNUNET_CRYPTO_eddsa_key_get_public: _GNUNET_CRYPTO_eddsa_key_get_public, _llvm_bswap_i32: _llvm_bswap_i32, _GNUNET_CRYPTO_rsa_private_key_create: _GNUNET_CRYPTO_rsa_private_key_create, _GNUNET_STRINGS_data_to_string_alloc: _GNUNET_STRINGS_data_to_string_alloc, _TALER_WRALL_sign_test: _TALER_WRALL_sign_test, _TALER_WR_verify_confirmation: _TALER_WR_verify_confirmation, _GNUNET_CRYPTO_rsa_public_key_decode: _GNUNET_CRYPTO_rsa_public_key_decode, _GNUNET_CRYPTO_rsa_blinding_key_free: _GNUNET_CRYPTO_rsa_blinding_key_free, _GNUNET_CRYPTO_rsa_signature_encode: _GNUNET_CRYPTO_rsa_signature_encode, _GNUNET_CRYPTO_rsa_verify: _GNUNET_CRYPTO_rsa_verify, _TALER_WR_eddsa_verify: _TALER_WR_eddsa_verify, _GNUNET_STRINGS_string_to_data: _GNUNET_STRINGS_string_to_data, _TALER_WRALL_gen_symmetric_key: _TALER_WRALL_gen_symmetric_key, _TALER_WRALL_ecc_ecdh: _TALER_WRALL_ecc_ecdh, _memset: _memset, _GNUNET_CRYPTO_rsa_unblind: _GNUNET_CRYPTO_rsa_unblind, _TALER_WR_get_currency: _TALER_WR_get_currency, _DEBUG_WR_get_purpose: _DEBUG_WR_get_purpose, _TALER_WRALL_get_amount: _TALER_WRALL_get_amount, _GNUNET_CRYPTO_rsa_private_key_encode: _GNUNET_CRYPTO_rsa_private_key_encode, _GNUNET_CRYPTO_symmetric_decrypt: _GNUNET_CRYPTO_symmetric_decrypt, _i64Subtract: _i64Subtract, _TALER_WR_get_value: _TALER_WR_get_value, _GNUNET_CRYPTO_rsa_signature_free: _GNUNET_CRYPTO_rsa_signature_free, _TALER_WRALL_eddsa_public_key_from_priv_string: _TALER_WRALL_eddsa_public_key_from_priv_string, _GNUNET_CRYPTO_rsa_blind: _GNUNET_CRYPTO_rsa_blind, _TALER_WR_verify_denom_enc: _TALER_WR_verify_denom_enc, _malloc: _malloc, _TALER_WR_hello_world: _TALER_WR_hello_world, _TALER_WRALL_make_withdraw_bundle: _TALER_WRALL_make_withdraw_bundle, _GNUNET_CRYPTO_rsa_signature_decode: _GNUNET_CRYPTO_rsa_signature_decode, _GNUNET_CRYPTO_rsa_sign: _GNUNET_CRYPTO_rsa_sign, _GNUNET_CRYPTO_ecdhe_key_create: _GNUNET_CRYPTO_ecdhe_key_create, _TALER_WRALL_get_encoding_from_rsa_signature: _TALER_WRALL_get_encoding_from_rsa_signature, _TALER_WRALL_hash: _TALER_WRALL_hash, _TALER_amount_normalize: _TALER_amount_normalize, _TALER_WRALL_sign_contract: _TALER_WRALL_sign_contract, _bitshift64Shl: _bitshift64Shl, _GNUNET_CRYPTO_rsa_private_key_free: _GNUNET_CRYPTO_rsa_private_key_free, _fflush: _fflush, _GNUNET_CRYPTO_hash_create_random: _GNUNET_CRYPTO_hash_create_random, _TALER_WRALL_eddsa_public_key_from_private: _TALER_WRALL_eddsa_public_key_from_private, _TALER_WR_multiply_amounts: _TALER_WR_multiply_amounts, _TALER_amount_add: _TALER_amount_add, _GNUNET_CRYPTO_ecdhe_key_get_public: _GNUNET_CRYPTO_ecdhe_key_get_public, _TALER_amount_subtract: _TALER_amount_subtract, _i64Add: _i64Add, _TALER_WRALL_purpose_create: _TALER_WRALL_purpose_create, _GNUNET_CRYPTO_eddsa_sign: _GNUNET_CRYPTO_eddsa_sign, _TALER_WR_verify_denom: _TALER_WR_verify_denom, _TALER_WRALL_get_current_time: _TALER_WRALL_get_current_time, ___errno_location: ___errno_location, _TALER_WR_get_fancy_time: _TALER_WR_get_fancy_time, _TALER_WRALL_make_eddsa_signature: _TALER_WRALL_make_eddsa_signature, _memmove: _memmove, _TALER_amount_get_zero: _TALER_amount_get_zero, _DEBUG_WR_dump_amount: _DEBUG_WR_dump_amount, _GNUNET_CRYPTO_rsa_public_key_encode: _GNUNET_CRYPTO_rsa_public_key_encode, _GNUNET_CRYPTO_hash: _GNUNET_CRYPTO_hash, _GNUNET_util_cl_init: _GNUNET_util_cl_init, _GNUNET_CRYPTO_random_init: _GNUNET_CRYPTO_random_init, _gpg_err_init: _gpg_err_init, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, establishStackSpace: establishStackSpace, setThrew: setThrew, setTempRet0: setTempRet0, getTempRet0: getTempRet0, dynCall_iiii: dynCall_iiii, dynCall_viiiii: dynCall_viiiii, dynCall_vi: dynCall_vi, dynCall_vii: dynCall_vii, dynCall_ii: dynCall_ii, dynCall_viii: dynCall_viii, dynCall_v: dynCall_v, dynCall_iiiii: dynCall_iiiii, dynCall_viiiiii: dynCall_viiiiii, dynCall_iii: dynCall_iii, dynCall_viiii: dynCall_viiii };
})
// EMSCRIPTEN_END_ASM
(Module.asmGlobalArg, Module.asmLibraryArg, buffer);
@@ -145843,6 +145831,12 @@ assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it a
return real__GNUNET_CRYPTO_random_init.apply(null, arguments);
};
+var real__TALER_amount_get_zero = asm["_TALER_amount_get_zero"]; asm["_TALER_amount_get_zero"] = function() {
+assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
+assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
+return real__TALER_amount_get_zero.apply(null, arguments);
+};
+
var real__DEBUG_WR_dump_amount = asm["_DEBUG_WR_dump_amount"]; asm["_DEBUG_WR_dump_amount"] = function() {
assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
@@ -145954,6 +145948,7 @@ var _TALER_WR_get_fancy_time = Module["_TALER_WR_get_fancy_time"] = asm["_TALER_
var _TALER_WRALL_make_eddsa_signature = Module["_TALER_WRALL_make_eddsa_signature"] = asm["_TALER_WRALL_make_eddsa_signature"];
var _memmove = Module["_memmove"] = asm["_memmove"];
var _GNUNET_CRYPTO_random_init = Module["_GNUNET_CRYPTO_random_init"] = asm["_GNUNET_CRYPTO_random_init"];
+var _TALER_amount_get_zero = Module["_TALER_amount_get_zero"] = asm["_TALER_amount_get_zero"];
var _DEBUG_WR_dump_amount = Module["_DEBUG_WR_dump_amount"] = asm["_DEBUG_WR_dump_amount"];
var _GNUNET_CRYPTO_rsa_public_key_encode = Module["_GNUNET_CRYPTO_rsa_public_key_encode"] = asm["_GNUNET_CRYPTO_rsa_public_key_encode"];
var _TALER_WRALL_get_current_time = Module["_TALER_WRALL_get_current_time"] = asm["_TALER_WRALL_get_current_time"];
diff --git a/extension/background/wallet.js b/extension/background/wallet.js
index 3bcbde91b..f915187ab 100644
--- a/extension/background/wallet.js
+++ b/extension/background/wallet.js
@@ -1,38 +1,6 @@
/// <reference path="../decl/urijs/URIjs.d.ts" />
/// <reference path="../decl/chrome/chrome.d.ts" />
'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:
- db.createObjectStore("mints", { keyPath: "baseUrl" });
- 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 });
- break;
- }
- };
- });
-}
/**
* See http://api.taler.net/wallet.html#general
*/
@@ -46,8 +14,141 @@ function canonicalizeBaseUrl(url) {
x.query();
return x.href();
}
-function grantCoins(db, feeThreshold, paymentAmount, mintBaseUrl) {
- throw "not implemented";
+function signDeposit(db, 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.cmp(new Amount(cd.coin.currentAmount)) < 0) {
+ coinSpend = new Amount(amountRemaining.toJson());
+ }
+ else {
+ coinSpend = new Amount(cd.coin.currentAmount);
+ }
+ let d = new DepositRequestPS({
+ h_contract: HashCode.fromCrock(offer.H_contract),
+ h_wire: HashCode.fromCrock(offer.contract.H_wire),
+ amount_with_fee: new Amount(cd.coin.currentAmount).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),
+ });
+ amountSpent.add(coinSpend);
+ let newAmount = new Amount(cd.coin.currentAmount);
+ newAmount.sub(coinSpend);
+ cd.coin.currentAmount = newAmount.toJson();
+ 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: amountSpent.toJson(),
+ };
+ ret.push({ sig: coinSig, 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 db
+ * @param paymentAmount
+ * @param depositFeeLimit
+ * @param mintKeys
+ */
+function getPossibleMintCoins(db, paymentAmount, depositFeeLimit, allowedMints) {
+ return new Promise((resolve, reject) => {
+ let m = {};
+ let found = false;
+ let tx = db.transaction(["mints", "coins"]);
+ // First pass: Get all coins from acceptable mints.
+ for (let info of allowedMints) {
+ let req_mints = tx.objectStore("mints")
+ .index("pubKey")
+ .get(info.master_pub);
+ req_mints.onsuccess = (e) => {
+ let mint = req_mints.result;
+ let req_coins = tx.objectStore("coins")
+ .index("mintBaseUrl")
+ .openCursor(IDBKeyRange.only(mint.baseUrl));
+ req_coins.onsuccess = (e) => {
+ let cursor = req_coins.result;
+ if (!cursor) {
+ return;
+ }
+ let cd = {
+ coin: cursor.value,
+ denom: mint.keys.denoms[cursor.value.denomPub]
+ };
+ let x = m[mint.baseUrl];
+ if (!x) {
+ m[mint.baseUrl] = [cd];
+ }
+ else {
+ x.push(cd);
+ }
+ };
+ };
+ }
+ tx.oncomplete = (e) => {
+ 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 = new Amount(coins[0].c.coin.currentAmount);
+ for (let i = 0; i < coins.length; i++) {
+ if (accFee.cmp(maxFee) >= 0) {
+ continue nextMint;
+ }
+ if (accAmount.cmp(minAmount) >= 0) {
+ ret[key] = m[key];
+ continue nextMint;
+ }
+ accFee.add(coins[i].a);
+ accFee.add(new Amount(coins[i].c.coin.currentAmount));
+ }
+ }
+ resolve(ret);
+ };
+ tx.onerror = (e) => {
+ reject();
+ };
+ });
+}
+function executePay(db, offer, payCoinInfo, merchantBaseUrl, chosenMint) {
+ return new Promise((resolve, reject) => {
+ let reqData = {};
+ reqData["H_wire"] = offer.contract.H_wire;
+ reqData["H_contract"] = offer.H_contract;
+ reqData["transaction_id"] = offer.contract.transaction_id;
+ reqData["refund_deadline"] = offer.contract.refund_deadline;
+ reqData["mint"] = chosenMint;
+ reqData["coins"] = payCoinInfo.map((x) => x.sig);
+ let payUrl = URI(merchantBaseUrl).absoluteTo(merchantBaseUrl);
+ console.log("Merchant URL", payUrl);
+ let req = new XMLHttpRequest();
+ req.open('post', payUrl.href());
+ req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
+ req.addEventListener('readystatechange', (e) => {
+ if (req.readyState == XMLHttpRequest.DONE) {
+ resolve();
+ }
+ });
+ });
}
function confirmPay(db, detail, sendResponse) {
console.log("confirmPay", JSON.stringify(detail));
@@ -57,10 +158,17 @@ function confirmPay(db, detail, sendResponse) {
contract: detail.offer.contract,
sig: detail.offer
};
- let contract = detail.offer.contract;
- //let chosenCoinPromise = chooseCoins(db, contract.max_fee, contract.amount)
- // .then(x => generateDepositPermissions(db, x))
- // .then(executePayment);
+ let offer = detail.offer;
+ getPossibleMintCoins(db, offer.contract.amount, offer.contract.max_fee, offer.contract.mints)
+ .then((mcs) => {
+ if (Object.keys(mcs).length == 0) {
+ sendResponse({ error: "Not enough coins." });
+ return;
+ }
+ let mintUrl = Object.keys(mcs)[0];
+ let ds = signDeposit(db, offer, mcs[mintUrl]);
+ return executePay(db, offer, ds, detail.merchantPageUrl, mintUrl);
+ });
return true;
}
function confirmReserve(db, detail, sendResponse) {
@@ -110,7 +218,10 @@ function confirmReserve(db, detail, sendResponse) {
sendResponse(resp);
var mint;
updateMintFromUrl(db, reserveRecord.mint_base_url)
- .then((m) => { mint = m; return updateReserve(db, reservePub, mint); })
+ .then((m) => {
+ mint = m;
+ return updateReserve(db, reservePub, mint);
+ })
.then((reserve) => depleteReserve(db, reserve, mint));
});
break;
@@ -213,7 +324,7 @@ function withdrawExecute(db, pc) {
console.log("Withdrawal successful");
console.log(myRequest.responseText);
let resp = JSON.parse(myRequest.responseText);
- let denomSig = rsaUnblind(RsaSignature.fromCrock(resp.coin_ev), RsaBlindingKey.fromCrock(pc.blindingKey), RsaPublicKey.fromCrock(pc.denomPub));
+ let denomSig = rsaUnblind(RsaSignature.fromCrock(resp.ev_sig), RsaBlindingKey.fromCrock(pc.blindingKey), RsaPublicKey.fromCrock(pc.denomPub));
let coin = {
coinPub: pc.coinPub,
coinPriv: pc.coinPriv,
@@ -397,7 +508,9 @@ function dumpDb(db, detail, sendResponse) {
let name = db.objectStoreNames[i];
let storeDump = {};
dump.stores[name] = storeDump;
- let store = tx.objectStore(name).openCursor().addEventListener('success', (e) => {
+ let store = tx.objectStore(name)
+ .openCursor()
+ .addEventListener('success', (e) => {
let cursor = e.target.result;
if (cursor) {
storeDump[cursor.key] = cursor.value;
diff --git a/extension/background/wallet.ts b/extension/background/wallet.ts
index 07c8743e1..281a24c6e 100644
--- a/extension/background/wallet.ts
+++ b/extension/background/wallet.ts
@@ -2,39 +2,11 @@
/// <reference path="../decl/chrome/chrome.d.ts" />
'use strict';
-const DB_NAME = "taler";
-const DB_VERSION = 1;
-
-/**
- * Return a promise that resolves
- * to the taler wallet db.
- */
-function openTalerDb(): Promise<IDBDatabase> {
- 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: // DB does not exist yet
- db.createObjectStore("mints", { keyPath: "baseUrl" });
- 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 });
- break;
- }
- };
- });
+interface AmountJson {
+ value: number;
+ fraction: number;
+ currency: string;
}
@@ -52,38 +24,244 @@ function canonicalizeBaseUrl(url) {
return x.href()
}
+
interface ConfirmPayRequest {
- offer: any;
- selectedMint: any;
+ merchantPageUrl: string;
+ offer: Offer;
+}
+
+interface MintCoins {
+ [mintUrl: string]: Db.CoinWithDenom[];
+}
+
+interface Offer {
+ contract: Contract;
+ sig: string;
+ H_contract: string;
+}
+
+interface Contract {
+ H_wire: string;
+ amount: AmountJson;
+ auditors: string[];
+ expiry: string,
+ locations: string[];
+ max_fee: AmountJson;
+ merchant: any;
+ merchant_pub: string;
+ mints: MintInfo[];
+ pay_url: string;
+ products: string[];
+ refund_deadline: string;
+ timestamp: string;
+ transaction_id: number;
+}
+
+
+interface CoinPaySig {
+ coin_sig: string;
+ coin_pub: string;
+ ub_sig: string;
+ denom_pub: string;
+ f: AmountJson;
+}
+
+
+type PayCoinInfo = Array<{ updatedCoin: Db.Coin, sig: CoinPaySig }>;
+
+
+function signDeposit(db: IDBDatabase,
+ offer: Offer,
+ cds: Db.CoinWithDenom[]): PayCoinInfo {
+ 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.cmp(new Amount(cd.coin.currentAmount)) < 0) {
+ coinSpend = new Amount(amountRemaining.toJson());
+ } else {
+ coinSpend = new Amount(cd.coin.currentAmount);
+ }
+
+ let d = new DepositRequestPS({
+ h_contract: HashCode.fromCrock(offer.H_contract),
+ h_wire: HashCode.fromCrock(offer.contract.H_wire),
+ amount_with_fee: new Amount(cd.coin.currentAmount).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),
+ });
+
+ amountSpent.add(coinSpend);
+
+ let newAmount = new Amount(cd.coin.currentAmount);
+ newAmount.sub(coinSpend);
+ cd.coin.currentAmount = newAmount.toJson();
+
+ let coinSig = eddsaSign(d.toPurpose(),
+ EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
+ .toCrock();
+
+ let s: CoinPaySig = {
+ coin_sig: coinSig,
+ coin_pub: cd.coin.coinPub,
+ ub_sig: cd.coin.denomSig,
+ denom_pub: cd.coin.denomPub,
+ f: amountSpent.toJson(),
+ };
+ ret.push({sig: coinSig, updatedCoin: cd.coin});
+ }
+ return ret;
+}
+
+interface MintInfo {
+ master_pub: string;
+ url: string;
+}
+
+
+/**
+ * Get mints and associated coins that are still spendable,
+ * but only if the sum the coins' remaining value exceeds the payment amount.
+ * @param db
+ * @param paymentAmount
+ * @param depositFeeLimit
+ * @param mintKeys
+ */
+function getPossibleMintCoins(db: IDBDatabase,
+ paymentAmount: AmountJson,
+ depositFeeLimit: AmountJson,
+ allowedMints: MintInfo[]): Promise<MintCoins> {
+ return new Promise((resolve, reject) => {
+ let m: MintCoins = {};
+ let found = false;
+ let tx = db.transaction(["mints", "coins"]);
+ // First pass: Get all coins from acceptable mints.
+ for (let info of allowedMints) {
+ let req_mints = tx.objectStore("mints")
+ .index("pubKey")
+ .get(info.master_pub);
+ req_mints.onsuccess = (e) => {
+ let mint: Db.Mint = req_mints.result;
+ let req_coins = tx.objectStore("coins")
+ .index("mintBaseUrl")
+ .openCursor(IDBKeyRange.only(mint.baseUrl));
+ req_coins.onsuccess = (e) => {
+ let cursor: IDBCursorWithValue = req_coins.result;
+ if (!cursor) {
+ return;
+ }
+ let cd = {
+ coin: cursor.value,
+ denom: mint.keys.denoms[cursor.value.denomPub]
+ };
+ let x = m[mint.baseUrl];
+ if (!x) {
+ m[mint.baseUrl] = [cd];
+ } else {
+ x.push(cd);
+ }
+ }
+ }
+ }
+
+ tx.oncomplete = (e) => {
+ let ret: MintCoins = {};
+
+ 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 = new Amount(coins[0].c.coin.currentAmount);
+ for (let i = 0; i < coins.length; i++) {
+ if (accFee.cmp(maxFee) >= 0) {
+ continue nextMint;
+ }
+ if (accAmount.cmp(minAmount) >= 0) {
+ ret[key] = m[key];
+ continue nextMint;
+ }
+ accFee.add(coins[i].a);
+ accFee.add(new Amount(coins[i].c.coin.currentAmount));
+ }
+ }
+ resolve(ret);
+ };
+
+ tx.onerror = (e) => {
+ reject();
+ }
+ });
}
-function grantCoins(db: IDBDatabase,
- feeThreshold: AmountJson,
- paymentAmount: AmountJson,
- mintBaseUrl: string): Promise<any> {
- throw "not implemented";
+function executePay(db,
+ offer: Offer,
+ payCoinInfo: PayCoinInfo,
+ merchantBaseUrl: string,
+ chosenMint: string) {
+ return new Promise((resolve, reject) => {
+ let reqData = {};
+ reqData["H_wire"] = offer.contract.H_wire;
+ reqData["H_contract"] = offer.H_contract;
+ reqData["transaction_id"] = offer.contract.transaction_id;
+ reqData["refund_deadline"] = offer.contract.refund_deadline;
+ reqData["mint"] = chosenMint;
+ reqData["coins"] = payCoinInfo.map((x) => x.sig);
+ let payUrl = URI(merchantBaseUrl).absoluteTo(merchantBaseUrl);
+ console.log("Merchant URL", payUrl);
+ let req = new XMLHttpRequest();
+ req.open('post', payUrl.href());
+ req.setRequestHeader("Content-Type",
+ "application/json;charset=UTF-8");
+ req.addEventListener('readystatechange', (e) => {
+ if (req.readyState == XMLHttpRequest.DONE) {
+ resolve()
+ }
+ });
+ });
}
-function confirmPay(db, detail: ConfirmPayRequest, sendResponse) {
+function confirmPay(db, detail: ConfirmPayRequest, sendResponse) {
console.log("confirmPay", JSON.stringify(detail));
let tx = db.transaction(['transactions'], 'readwrite');
let trans = {
contractHash: detail.offer.H_contract,
contract: detail.offer.contract,
sig: detail.offer
- }
-
- let contract = detail.offer.contract;
-
- //let chosenCoinPromise = chooseCoins(db, contract.max_fee, contract.amount)
- // .then(x => generateDepositPermissions(db, x))
- // .then(executePayment);
+ };
+ let offer: Offer = detail.offer;
+ getPossibleMintCoins(db,
+ offer.contract.amount,
+ offer.contract.max_fee,
+ offer.contract.mints)
+ .then((mcs) => {
+ if (Object.keys(mcs).length == 0) {
+ sendResponse({error: "Not enough coins."});
+ return;
+ }
+ let mintUrl = Object.keys(mcs)[0];
+ let ds = signDeposit(db, offer, mcs[mintUrl]);
+ return executePay(db, offer, ds, detail.merchantPageUrl, mintUrl);
+ });
return true;
}
+
function confirmReserve(db, detail, sendResponse) {
let reservePriv = EddsaPrivateKey.create();
let reservePub = reservePriv.getPublicKey();
@@ -131,8 +309,11 @@ function confirmReserve(db, detail, sendResponse) {
sendResponse(resp);
var mint;
updateMintFromUrl(db, reserveRecord.mint_base_url)
- .then((m) => { mint = m; return updateReserve(db, reservePub, mint); })
- .then((reserve) => depleteReserve(db, reserve, mint));
+ .then((m) => {
+ mint = m;
+ return updateReserve(db, reservePub, mint);
+ })
+ .then((reserve) => depleteReserve(db, reserve, mint));
});
break;
default:
@@ -160,8 +341,8 @@ function rankDenom(denom1: any, denom2: any) {
function withdrawPrepare(db: IDBDatabase,
- denom: Denomination,
- reserve): Promise<PreCoin> {
+ denom: Db.Denomination,
+ reserve): Promise<Db.PreCoin> {
let reservePriv = new EddsaPrivateKey();
reservePriv.loadCrock(reserve.reserve_priv);
let reservePub = new EddsaPublicKey();
@@ -196,7 +377,7 @@ function withdrawPrepare(db: IDBDatabase,
console.log("crypto done, doing request");
- let preCoin: PreCoin = {
+ let preCoin: Db.PreCoin = {
reservePub: reservePub.toCrock(),
blindingKey: blindingFactor.toCrock(),
coinPub: coinPub.toCrock(),
@@ -219,57 +400,59 @@ function withdrawPrepare(db: IDBDatabase,
});
}
+
function dbGet(db, store: string, key: any): Promise<any> {
let tx = db.transaction([store]);
let req = tx.objectStore(store).get(key);
return new Promise((resolve, reject) => {
- req.onsuccess = (e) => resolve(req.result);
+ req.onsuccess = (e) => resolve(req.result);
});
}
-function withdrawExecute(db, pc: PreCoin): Promise<Coin> {
+function withdrawExecute(db, pc: Db.PreCoin): Promise<Db.Coin> {
return dbGet(db, 'reserves', pc.reservePub)
- .then((r) => new Promise((resolve, reject) => {
- console.log("loading precoin", JSON.stringify(pc));
- let wd: any = {};
- 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);
- let myRequest = new XMLHttpRequest();
- console.log("making request to " + reqUrl.href());
- myRequest.open('post', reqUrl.href());
- myRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
- myRequest.send(JSON.stringify(wd));
- myRequest.addEventListener('readystatechange', (e) => {
- if (myRequest.readyState == XMLHttpRequest.DONE) {
- if (myRequest.status != 200) {
- console.log("Withdrawal failed, status ", myRequest.status);
- reject();
- return;
- }
- console.log("Withdrawal successful");
- console.log(myRequest.responseText);
- let resp = JSON.parse(myRequest.responseText);
- let denomSig = rsaUnblind(RsaSignature.fromCrock(resp.coin_ev),
- RsaBlindingKey.fromCrock(pc.blindingKey),
- RsaPublicKey.fromCrock(pc.denomPub));
- let coin: Coin = {
- coinPub: pc.coinPub,
- coinPriv: pc.coinPriv,
- denomPub: pc.denomPub,
- denomSig: denomSig.encode().toCrock(),
- currentAmount: pc.coinValue
- }
- console.log("unblinded coin");
- resolve(coin);
- } else {
- console.log("ready state change to", myRequest.status);
- }
- });
- }));
+ .then((r) => new Promise((resolve, reject) => {
+ console.log("loading precoin", JSON.stringify(pc));
+ let wd: any = {};
+ 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);
+ let myRequest = new XMLHttpRequest();
+ console.log("making request to " + reqUrl.href());
+ myRequest.open('post', reqUrl.href());
+ myRequest.setRequestHeader("Content-Type",
+ "application/json;charset=UTF-8");
+ myRequest.send(JSON.stringify(wd));
+ myRequest.addEventListener('readystatechange', (e) => {
+ if (myRequest.readyState == XMLHttpRequest.DONE) {
+ if (myRequest.status != 200) {
+ console.log("Withdrawal failed, status ", myRequest.status);
+ reject();
+ return;
+ }
+ console.log("Withdrawal successful");
+ console.log(myRequest.responseText);
+ let resp = JSON.parse(myRequest.responseText);
+ let denomSig = rsaUnblind(RsaSignature.fromCrock(resp.ev_sig),
+ RsaBlindingKey.fromCrock(pc.blindingKey),
+ RsaPublicKey.fromCrock(pc.denomPub));
+ let coin: Db.Coin = {
+ coinPub: pc.coinPub,
+ coinPriv: pc.coinPriv,
+ denomPub: pc.denomPub,
+ denomSig: denomSig.encode().toCrock(),
+ currentAmount: pc.coinValue
+ };
+ console.log("unblinded coin");
+ resolve(coin);
+ } else {
+ console.log("ready state change to", myRequest.status);
+ }
+ });
+ }));
}
@@ -284,14 +467,14 @@ function updateBadge(db) {
cursor.continue();
} else {
console.log("badge");
- chrome.browserAction.setBadgeText({text: ""+n});
+ chrome.browserAction.setBadgeText({text: "" + n});
chrome.browserAction.setBadgeBackgroundColor({color: "#0F0"});
}
}
}
-function storeCoin(db, coin: Coin) {
+function storeCoin(db, coin: Db.Coin) {
let tx = db.transaction(['coins', 'precoins'], 'readwrite');
tx.objectStore('precoins').delete(coin.coinPub);
tx.objectStore('coins').add(coin);
@@ -306,8 +489,8 @@ function storeCoin(db, coin: Coin) {
function withdraw(db, denom, reserve): Promise<void> {
return withdrawPrepare(db, denom, reserve)
- .then((pc) => withdrawExecute(db, pc))
- .then((c) => storeCoin(db, c));
+ .then((pc) => withdrawExecute(db, pc))
+ .then((c) => storeCoin(db, c));
}
@@ -344,7 +527,7 @@ function depleteReserve(db, reserve, mint) {
console.log("doing work");
let d = workList.pop();
withdraw(db, d, reserve)
- .then(() => next());
+ .then(() => next());
}
next();
@@ -408,7 +591,7 @@ function updateMintFromUrl(db, baseUrl) {
console.log("keys invalid");
reject();
} else {
- let mint = {
+ let mint: Db.Mint = {
baseUrl: baseUrl,
keys: mintKeysJson
};
@@ -419,7 +602,7 @@ function updateMintFromUrl(db, baseUrl) {
let di = {
denomPub: d.denom_pub,
value: d.value
- }
+ };
tx.objectStore('denoms').put(di);
}
tx.oncomplete = (e) => {
@@ -446,19 +629,21 @@ function dumpDb(db, detail, sendResponse) {
console.log("stores: " + JSON.stringify(db.objectStoreNames));
let tx = db.transaction(db.objectStoreNames);
tx.addEventListener('complete', (e) => {
- sendResponse(dump);
+ sendResponse(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();
- }
- });
+ let store = tx.objectStore(name)
+ .openCursor()
+ .addEventListener('success', (e) => {
+ let cursor = e.target.result;
+ if (cursor) {
+ storeDump[cursor.key] = cursor.value;
+ cursor.continue();
+ }
+ });
}
return true;
}
@@ -513,7 +698,7 @@ chrome.browserAction.setBadgeText({text: ""});
openTalerDb().then((db) => {
console.log("db loaded");
chrome.runtime.onMessage.addListener(
- function (req, sender, onresponse) {
+ function(req, sender, onresponse) {
let dispatch = {
"confirm-reserve": confirmReserve,
"confirm-pay": confirmPay,
@@ -524,7 +709,9 @@ openTalerDb().then((db) => {
if (req.type in dispatch) {
return dispatch[req.type](db, req.detail, onresponse);
}
- console.error(format("Request type {1} unknown, req {0}", JSON.stringify(req), req.type));
+ console.error(format("Request type {1} unknown, req {0}",
+ JSON.stringify(req),
+ req.type));
return false;
});
});
diff --git a/extension/lib/util.js b/extension/lib/util.js
index 801d7d189..71bfce4d3 100644
--- a/extension/lib/util.js
+++ b/extension/lib/util.js
@@ -28,3 +28,7 @@ function format(s, ...args) {
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; });
+}
diff --git a/extension/lib/util.ts b/extension/lib/util.ts
index 106e22970..b30d60432 100644
--- a/extension/lib/util.ts
+++ b/extension/lib/util.ts
@@ -32,3 +32,8 @@ function format(s: string, ...args: any[]) {
return s;
}
+
+function promiseFinally<T>(p: Promise<T>, fn): Promise<T> {
+ return p.then((x) => { fn(); return x; })
+ .catch((e) => {fn(); throw e;});
+} \ No newline at end of file
diff --git a/extension/pages/confirm-contract.html b/extension/pages/confirm-contract.html
index 8d68511dd..9959bb489 100644
--- a/extension/pages/confirm-contract.html
+++ b/extension/pages/confirm-contract.html
@@ -26,6 +26,10 @@
<p />
</script>
+ <script id="error-template" type="text/x-handlebars-template">
+ Payment was not successful: {{error}}
+ </script>
+
</head>
<body>
@@ -33,7 +37,9 @@
<div id="render-contract"></div>
- <button id="confirm-purchase">Confirm Purchase!</button>
+ <button id="confirm-pay">Confirm Pay!</button>
+
+ <div id="status"></div>
</body>
</html>
diff --git a/extension/pages/confirm-contract.js b/extension/pages/confirm-contract.js
index c59ac90a9..0f6d83744 100644
--- a/extension/pages/confirm-contract.js
+++ b/extension/pages/confirm-contract.js
@@ -23,16 +23,16 @@ document.addEventListener("DOMContentLoaded", (e) => {
let html = template(offer.contract);
$_("render-contract").innerHTML = html;
document.getElementById("confirm-pay").addEventListener("click", (e) => {
- let d = clone(query);
+ let d = {
+ offer: JSON.parse(query.offer)
+ };
chrome.runtime.sendMessage({ type: 'confirm-pay', detail: d }, (resp) => {
- if (resp.success === true) {
- document.location.href = resp.backlink;
- }
- else {
- document.body.innerHTML =
- `Oops, something went wrong.
- Here is some more info:
- <pre>${resp.text}</pre>`;
+ console.log("got response", resp);
+ if ("error" in resp) {
+ let source = $_("error-template").innerHTML;
+ let template = Handlebars.compile(source);
+ $_("status").innerHTML = template(resp);
+ return;
}
});
});
diff --git a/extension/pages/confirm-contract.tsx b/extension/pages/confirm-contract.tsx
index 811e2e001..c9d41a2c8 100644
--- a/extension/pages/confirm-contract.tsx
+++ b/extension/pages/confirm-contract.tsx
@@ -34,15 +34,16 @@ document.addEventListener("DOMContentLoaded", (e) => {
$_("render-contract").innerHTML = html;
document.getElementById("confirm-pay").addEventListener("click", (e) => {
- let d = clone(query);
+ let d = {
+ offer: JSON.parse(query.offer)
+ };
chrome.runtime.sendMessage({type:'confirm-pay', detail: d}, (resp) => {
- if (resp.success === true) {
- document.location.href = resp.backlink;
- } else {
- document.body.innerHTML =
- `Oops, something went wrong.
- Here is some more info:
- <pre>${resp.text}</pre>`;
+ console.log("got response", resp);
+ if ("error" in resp) {
+ let source = $_("error-template").innerHTML;
+ let template = Handlebars.compile(source);
+ $_("status").innerHTML = template(resp);
+ return;
}
});
});
diff --git a/extension/pages/debug.html b/extension/pages/debug.html
index 7dfa7a9cc..24682dd24 100644
--- a/extension/pages/debug.html
+++ b/extension/pages/debug.html
@@ -7,5 +7,6 @@
<h1>Debug Pages</h1>
<a href="show-db.html">Show DB</a> <br>
<a href="../popup/balance-overview.html">Show balance</a>
+
</body>
</html>
diff --git a/extension/popup/balance-overview.js b/extension/popup/balance-overview.js
index 4fd991b23..b2c5e0837 100644
--- a/extension/popup/balance-overview.js
+++ b/extension/popup/balance-overview.js
@@ -20,6 +20,15 @@ document.addEventListener('DOMContentLoaded', (e) => {
let context = document.getElementById("balance-template").innerHTML;
let template = Handlebars.compile(context);
document.getElementById("content").innerHTML = template(wallet);
+ let el = document.getElementById("link-kudos");
+ if (el) {
+ el.onclick = (e) => {
+ let target = e.target;
+ chrome.tabs.create({
+ "url": target.href
+ });
+ };
+ }
});
document.getElementById("debug").addEventListener("click", (e) => {
chrome.tabs.create({
@@ -29,10 +38,4 @@ document.addEventListener('DOMContentLoaded', (e) => {
document.getElementById("reset").addEventListener("click", (e) => {
chrome.runtime.sendMessage({ type: "reset" });
});
- document.getElementById("link-kudos").addEventListener("click", (e) => {
- let target = e.target;
- chrome.tabs.create({
- "url": target.href
- });
- });
});
diff --git a/extension/popup/balance-overview.tsx b/extension/popup/balance-overview.tsx
index 88ff1bccb..38be50375 100644
--- a/extension/popup/balance-overview.tsx
+++ b/extension/popup/balance-overview.tsx
@@ -16,12 +16,22 @@ let React = {
}
}
+
document.addEventListener('DOMContentLoaded', (e) => {
console.log("content loaded");
chrome.runtime.sendMessage({type: "balances"}, function(wallet) {
let context = document.getElementById("balance-template").innerHTML;
let template = Handlebars.compile(context);
document.getElementById("content").innerHTML = template(wallet);
+ let el = document.getElementById("link-kudos");
+ if (el) {
+ el.onclick = (e) => {
+ let target: any = e.target;
+ chrome.tabs.create({
+ "url": target.href
+ });
+ };
+ }
});
document.getElementById("debug").addEventListener("click", (e) => {
@@ -32,10 +42,4 @@ document.addEventListener('DOMContentLoaded', (e) => {
document.getElementById("reset").addEventListener("click", (e) => {
chrome.runtime.sendMessage({type: "reset"});
});
- document.getElementById("link-kudos").addEventListener("click", (e) => {
- let target: any = e.target;
- chrome.tabs.create({
- "url": target.href
- });
- });
});