aboutsummaryrefslogtreecommitdiff
path: root/extension
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2015-12-16 00:38:36 +0100
committerFlorian Dold <florian.dold@gmail.com>2015-12-16 04:46:58 +0100
commitccce0f9749f756fb4c681dc23d2386dc2f85dc6d (patch)
tree269a1e8ba617474b4f5679d751d0d49fb2c58f08 /extension
parentad679a4d0e555a7ede1eac95f79105a35e45b311 (diff)
downloadwallet-core-ccce0f9749f756fb4c681dc23d2386dc2f85dc6d.tar.xz
Make withdrawal work.
Diffstat (limited to 'extension')
-rw-r--r--extension/background/emscriptif.js78
-rw-r--r--extension/background/emscriptif.ts121
-rw-r--r--extension/background/wallet.js147
-rw-r--r--extension/background/wallet.ts242
4 files changed, 438 insertions, 150 deletions
diff --git a/extension/background/emscriptif.js b/extension/background/emscriptif.js
index 0e4f2a209..11260c74d 100644
--- a/extension/background/emscriptif.js
+++ b/extension/background/emscriptif.js
@@ -21,14 +21,14 @@ const GNUNET_OK = 1;
const GNUNET_YES = 1;
const GNUNET_NO = 0;
const GNUNET_SYSERR = -1;
-let getEmsc = Module.cwrap;
+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', 'void', ['number', 'number', 'number']),
- amount_subtract: getEmsc('TALER_amount_subtract', 'void', ['number', 'number', '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_cmp: getEmsc('TALER_amount_cmp', 'number', ['number', 'number']),
amount_hton: getEmsc('TALER_amount_hton', 'void', ['number', 'number']),
@@ -36,21 +36,25 @@ var emsc = {
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']),
- string_to_data: getEmsc('GNUNET_STRINGS_string_to_data', 'void', ['number', 'number', 'number', '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_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', 'void', ['number']),
- rsa_blinding_key_encode: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_encode', 'void', ['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']),
malloc: (size) => Module._malloc(size),
};
@@ -72,6 +76,39 @@ class ArenaObject {
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 Arena {
constructor() {
@@ -348,6 +385,14 @@ class WithdrawRequestPS extends SignatureStruct {
["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 RsaPublicKey extends ArenaObject {
static fromCrock(s, a) {
let obj = new RsaPublicKey(a);
@@ -374,6 +419,22 @@ class RsaPublicKey extends ArenaObject {
class EddsaSignature extends PackedArenaObject {
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);
+ }
+}
function rsaBlind(hashCode, blindingKey, pkey, arena) {
let ptr = emscAlloc.malloc(PTR_SIZE);
let s = emscAlloc.rsa_blind(hashCode.nativePtr, blindingKey.nativePtr, pkey.nativePtr, ptr);
@@ -389,3 +450,6 @@ function eddsaSign(purpose, priv, a) {
}
return sig;
}
+function rsaUnblind(sig, bk, pk) {
+ throw Error("Not implemented");
+}
diff --git a/extension/background/emscriptif.ts b/extension/background/emscriptif.ts
index 251c57b32..4fcb3668c 100644
--- a/extension/background/emscriptif.ts
+++ b/extension/background/emscriptif.ts
@@ -28,7 +28,15 @@ const GNUNET_YES = 1;
const GNUNET_NO = 0;
const GNUNET_SYSERR = -1;
-let getEmsc = Module.cwrap;
+
+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);
+}
+
+let getEmsc: EmscFunGen = (...args) => Module.cwrap.apply(null, args);
var emsc = {
free: (ptr) => Module._free(ptr),
@@ -42,10 +50,10 @@ var emsc = {
'string',
['number']),
amount_add: getEmsc('TALER_amount_add',
- 'void',
+ 'number',
['number', 'number', 'number']),
amount_subtract: getEmsc('TALER_amount_subtract',
- 'void',
+ 'number',
['number', 'number', 'number']),
amount_normalize: getEmsc('TALER_amount_normalize',
'void',
@@ -68,15 +76,21 @@ var emsc = {
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',
- 'void',
+ 'number',
['number', 'number', 'number', 'number']),
eddsa_sign: getEmsc('GNUNET_CRYPTO_eddsa_sign',
- 'number',
- ['number', 'number', 'number']),
+ '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 = {
@@ -84,7 +98,7 @@ var emscAlloc = {
'number',
['number', 'number', 'number', 'string']),
eddsa_key_create: getEmsc('GNUNET_CRYPTO_eddsa_key_create',
- 'number'),
+ 'number', []),
eddsa_public_key_from_private: getEmsc('TALER_WRALL_eddsa_public_key_from_private',
'number',
['number']),
@@ -95,13 +109,16 @@ var emscAlloc = {
'number',
['number', 'number', 'number']),
rsa_blind: getEmsc('GNUNET_CRYPTO_rsa_blind',
- 'number',
- ['number', 'number', 'number', 'number']),
+ 'number',
+ ['number', 'number', 'number', 'number']),
rsa_blinding_key_create: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_create',
- 'void',
+ 'number',
['number']),
rsa_blinding_key_encode: getEmsc('GNUNET_CRYPTO_rsa_blinding_key_encode',
- 'void',
+ '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',
@@ -109,6 +126,9 @@ var emscAlloc = {
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']),
@@ -128,7 +148,7 @@ enum RandomQuality {
abstract class ArenaObject {
- nativePtr: number;
+ private _nativePtr: number;
arena: Arena;
abstract destroy(): void;
@@ -139,6 +159,46 @@ abstract class ArenaObject {
arena.put(this);
this.arena = arena;
}
+
+ getNative(): number {
+ // 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: number) {
+ if (this.nativePtr !== undefined) {
+ throw Error("Double allocation");
+ }
+ this.nativePtr = emscAlloc.malloc(size);
+ }
+
+ setNative(n: number) {
+ 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 Arena {
@@ -473,6 +533,17 @@ class WithdrawRequestPS extends SignatureStruct {
}
+
+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;
+}
+
+
class RsaPublicKey extends ArenaObject {
static fromCrock(s: string, a?: Arena): RsaPublicKey {
let obj = new RsaPublicKey(a);
@@ -507,6 +578,25 @@ class EddsaSignature extends PackedArenaObject {
}
+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;
+ }
+
+ encode(arena?: Arena): ByteArray {
+ return encodeWith(this, emscAlloc.rsa_signature_encode);
+ }
+
+ destroy() {
+ emsc.rsa_signature_free(this.getNative());
+ this.setNative(0);
+ }
+}
+
function rsaBlind(hashCode: HashCode,
blindingKey: RsaBlindingKey,
pkey: RsaPublicKey,
@@ -532,3 +622,10 @@ function eddsaSign(purpose: EccSignaturePurpose,
return sig;
}
+function rsaUnblind(sig: RsaSignature,
+ bk: RsaBlindingKey,
+ pk: RsaPublicKey): RsaSignature {
+ throw Error("Not implemented");
+}
+
+
diff --git a/extension/background/wallet.js b/extension/background/wallet.js
index dd1bccaea..5483059a5 100644
--- a/extension/background/wallet.js
+++ b/extension/background/wallet.js
@@ -17,9 +17,8 @@ function openTalerDb() {
resolve(req.result);
};
req.onupgradeneeded = (e) => {
- let db = e.target.result;
+ let db = req.result;
console.log("DB: upgrade needed: oldVersion = " + e.oldVersion);
- db = e.target.result;
switch (e.oldVersion) {
case 0:
db.createObjectStore("mints", { keyPath: "baseUrl" });
@@ -28,6 +27,7 @@ function openTalerDb() {
db.createObjectStore("coins", { keyPath: "coin_pub" });
db.createObjectStore("withdrawals", { keyPath: "id", autoIncrement: true });
db.createObjectStore("transactions", { keyPath: "id", autoIncrement: true });
+ db.createObjectStore("precoins", { keyPath: "coinPub", autoIncrement: true });
break;
}
};
@@ -113,52 +113,74 @@ function rankDenom(denom1, denom2) {
let v2 = new Amount(denom2.value);
return (-1) * v1.cmp(v2);
}
-function withdraw(denom, reserve, mint) {
- console.log("in withdraw");
- let wd = {};
- wd.denom_pub = denom.denom_pub;
- wd.reserve_pub = reserve.reserve_pub;
- let a = new Arena();
- try {
- 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(512);
- let pubHash = coinPub.hash();
- console.log("about to blind");
- let ev = rsaBlind(pubHash, blindingFactor, denomPub);
- console.log("blinded");
- 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();
- withdrawRequest.set("reserve_pub", reservePub);
- withdrawRequest.set("amount_with_fee", amountWithFee.toNbo());
- withdrawRequest.set("withdraw_fee", withdrawFee.toNbo());
- withdrawRequest.set("h_denomination_pub", denomPub.encode().hash());
- withdrawRequest.set("h_coin_envelope", ev.hash());
- console.log("about to sign");
- var sig = eddsaSign(withdrawRequest.toPurpose(), reservePriv);
- console.log("signed");
- wd.reserve_sig = sig.toCrock();
- wd.coin_ev = ev.toCrock();
- }
- finally {
- a.destroy();
+function withdrawPrepare(db, denom, reserve) {
+ console.log("in withdraw prepare");
+ let reservePriv = new EddsaPrivateKey();
+ console.log("loading reserve priv", reserve.reserve_priv);
+ reservePriv.loadCrock(reserve.reserve_priv);
+ console.log("reserve priv is", reservePriv.toCrock());
+ 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();
+ console.log("about to blind");
+ let ev = rsaBlind(pubHash, blindingFactor, denomPub);
+ console.log("blinded");
+ 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();
+ withdrawRequest.set("reserve_pub", reservePub);
+ withdrawRequest.set("amount_with_fee", amountWithFee.toNbo());
+ withdrawRequest.set("withdraw_fee", withdrawFee.toNbo());
+ withdrawRequest.set("h_denomination_pub", denomPub.encode().hash());
+ withdrawRequest.set("h_coin_envelope", ev.hash());
+ console.log("about to sign");
+ var sig = eddsaSign(withdrawRequest.toPurpose(), reservePriv);
+ console.log("signed");
console.log("crypto done, doing request");
- console.log("request:");
- console.log(JSON.stringify(wd));
+ let preCoin = {
+ reservePub: reservePub.toCrock(),
+ blindingKey: blindingFactor.toCrock(),
+ coinPub: coinPub.toCrock(),
+ coinPriv: coinPriv.toCrock(),
+ denomPub: denomPub.encode().toCrock(),
+ withdrawSig: sig.toCrock(),
+ coinEv: ev.toCrock()
+ };
+ console.log("storing precoin", JSON.stringify(preCoin));
+ let tx = db.transaction(['precoins'], 'readwrite');
+ tx.objectStore('precoins').add(preCoin);
+ return new Promise((resolve, reject) => {
+ tx.oncomplete = (e) => {
+ resolve(preCoin);
+ };
+ });
+}
+function dbGet(db, store, key) {
+ let tx = db.transaction([store]);
+ let req = tx.objectStore(store).get(key);
return new Promise((resolve, reject) => {
- let reqUrl = URI("reserve/withdraw").absoluteTo(mint.baseUrl);
+ req.onsuccess = (e) => resolve(req.result);
+ });
+}
+function withdrawExecute(db, pc) {
+ return dbGet(db, 'reserves', pc.reservePub)
+ .then((r) => new Promise((resolve, reject) => {
+ console.log("loading precoin", JSON.stringify(pc));
+ 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);
let myRequest = new XMLHttpRequest();
console.log("making request to " + reqUrl.href());
myRequest.open('post', reqUrl.href());
@@ -173,13 +195,32 @@ function withdraw(denom, reserve, mint) {
}
console.log("Withdrawal successful");
console.log(myRequest.responseText);
- resolve();
+ let resp = JSON.parse(myRequest.responseText);
+ //let denomSig = rsaUnblind(RsaSignature.fromCrock(resp.coin_ev),
+ // RsaBlindingKey.fromCrock(pc.blindingKey),
+ // RsaPublicKey.fromCrock(pc.denomPub));
+ let coin = {
+ coinPub: pc.coinPub,
+ coinPriv: pc.coinPriv,
+ denomPub: pc.denomPub,
+ reservePub: pc.reservePub,
+ denomSig: "foo" //denomSig.encode().toCrock()
+ };
+ console.log("unblinded coin");
+ resolve(coin);
}
else {
console.log("ready state change to", myRequest.status);
}
});
- });
+ }));
+}
+function storeCoin(db, coin) {
+}
+function withdraw(db, denom, reserve) {
+ return withdrawPrepare(db, denom, reserve)
+ .then((pc) => withdrawExecute(db, pc))
+ .then((c) => storeCoin(db, c));
}
/**
* Withdraw coins from a reserve until it is empty.
@@ -199,7 +240,7 @@ function depleteReserve(db, reserve, mint) {
}
found = true;
remaining.sub(cost);
- workList.push([d, reserve, mint]);
+ workList.push(d);
}
if (!found) {
break;
@@ -211,8 +252,8 @@ function depleteReserve(db, reserve, mint) {
return;
}
console.log("doing work");
- let w = workList.pop();
- withdraw(w[0], w[1], w[2])
+ let d = workList.pop();
+ withdraw(db, d, reserve)
.then(() => next());
}
next();
@@ -324,6 +365,10 @@ openTalerDb().then((db) => {
"confirm-reserve": confirmReserve,
"dump-db": dumpDb
};
- return dispatch[req.type](db, req.detail, onresponse);
+ if (req.type in dispatch) {
+ return dispatch[req.type](db, req.detail, onresponse);
+ }
+ console.error(format("Request type unknown, req {0}", JSON.stringify(req)));
+ return false;
});
});
diff --git a/extension/background/wallet.ts b/extension/background/wallet.ts
index 236f607e2..a000855b6 100644
--- a/extension/background/wallet.ts
+++ b/extension/background/wallet.ts
@@ -10,20 +10,19 @@ const DB_VERSION = 1;
* Return a promise that resolves
* to the taler wallet db.
*/
-function openTalerDb() {
+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 : any) => {
- resolve(e.target.result);
+ req.onsuccess = (e) => {
+ resolve(req.result);
};
- req.onupgradeneeded = (event : any) => {
- let db = event.target.result;
- console.log ("DB: upgrade needed: oldVersion = " + event.oldVersion);
- db = event.target.result;
- switch (event.oldVersion) {
+ 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"});
@@ -31,6 +30,7 @@ function openTalerDb() {
db.createObjectStore("coins", { keyPath: "coin_pub" });
db.createObjectStore("withdrawals", { keyPath: "id", autoIncrement: true });
db.createObjectStore("transactions", { keyPath: "id", autoIncrement: true });
+ db.createObjectStore("precoins", { keyPath: "coinPub", autoIncrement: true });
break;
}
};
@@ -126,78 +126,156 @@ function rankDenom(denom1: any, denom2: any) {
}
-function withdraw(denom, reserve, mint): Promise<void> {
- console.log("in withdraw");
- let wd: any = {};
- wd.denom_pub = denom.denom_pub;
- wd.reserve_pub = reserve.reserve_pub;
- let a = new Arena();
- try {
- 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: HashCode = coinPub.hash();
- console.log("about to blind");
- let ev: ByteArray = rsaBlind(pubHash, blindingFactor, denomPub);
- console.log("blinded");
-
- if (!denom.fee_withdraw) {
- throw Error("Field fee_withdraw missing");
- }
+interface ReservePub {
+ reservePub: string;
+}
+
+interface CoinPub {
+ coinPub: string;
+}
+
+
+interface PreCoin {
+ coinPub: string;
+ coinPriv: string;
+ reservePub: string;
+ denomPub: string;
+ blindingKey: string;
+ withdrawSig: string;
+ coinEv: string;
+}
+
+
+interface Coin {
+ coinPub: string;
+ coinPriv: string;
+ reservePub: string;
+ denomPub: string;
+ denomSig: string;
+}
+
- 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();
- withdrawRequest.set("reserve_pub", reservePub);
- withdrawRequest.set("amount_with_fee", amountWithFee.toNbo());
- withdrawRequest.set("withdraw_fee", withdrawFee.toNbo());
- withdrawRequest.set("h_denomination_pub", denomPub.encode().hash());
- withdrawRequest.set("h_coin_envelope", ev.hash());
- console.log("about to sign");
- var sig = eddsaSign(withdrawRequest.toPurpose(), reservePriv);
- console.log("signed");
- wd.reserve_sig = sig.toCrock();
- wd.coin_ev = ev.toCrock();
- } finally {
- a.destroy();
+function withdrawPrepare(db: IDBDatabase, denom, reserve): Promise<PreCoin> {
+ console.log("in withdraw prepare");
+ let reservePriv = new EddsaPrivateKey();
+ console.log("loading reserve priv", reserve.reserve_priv);
+ reservePriv.loadCrock(reserve.reserve_priv);
+ console.log("reserve priv is", reservePriv.toCrock());
+ 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: HashCode = coinPub.hash();
+ console.log("about to blind");
+ let ev: ByteArray = rsaBlind(pubHash, blindingFactor, denomPub);
+ console.log("blinded");
+
+ 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();
+ withdrawRequest.set("reserve_pub", reservePub);
+ withdrawRequest.set("amount_with_fee", amountWithFee.toNbo());
+ withdrawRequest.set("withdraw_fee", withdrawFee.toNbo());
+ withdrawRequest.set("h_denomination_pub", denomPub.encode().hash());
+ withdrawRequest.set("h_coin_envelope", ev.hash());
+ console.log("about to sign");
+ var sig = eddsaSign(withdrawRequest.toPurpose(), reservePriv);
+ console.log("signed");
+
console.log("crypto done, doing request");
- console.log("request:");
- console.log(JSON.stringify(wd));
+ let preCoin: PreCoin = {
+ reservePub: reservePub.toCrock(),
+ blindingKey: blindingFactor.toCrock(),
+ coinPub: coinPub.toCrock(),
+ coinPriv: coinPriv.toCrock(),
+ denomPub: denomPub.encode().toCrock(),
+ withdrawSig: sig.toCrock(),
+ coinEv: ev.toCrock()
+ };
- return new Promise<void>((resolve, reject) => {
- let reqUrl = URI("reserve/withdraw").absoluteTo(mint.baseUrl);
- 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);
- resolve();
- } else {
- console.log("ready state change to", myRequest.status);
- }
- });
+ console.log("storing precoin", JSON.stringify(preCoin));
+
+ let tx = db.transaction(['precoins'], 'readwrite');
+ tx.objectStore('precoins').add(preCoin);
+ return new Promise((resolve, reject) => {
+ tx.oncomplete = (e) => {
+ resolve(preCoin);
+ }
});
+}
+
+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);
+ });
+}
+
+function withdrawExecute(db, pc: PreCoin): Promise<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,
+ reservePub: pc.reservePub,
+ denomSig: "foo" //denomSig.encode().toCrock()
+ }
+ console.log("unblinded coin");
+ resolve(coin);
+ } else {
+ console.log("ready state change to", myRequest.status);
+ }
+ });
+ }));
+}
+
+
+function storeCoin(db, coin) {
+}
+
+
+function withdraw(db, denom, reserve): Promise<void> {
+ return withdrawPrepare(db, denom, reserve)
+ .then((pc) => withdrawExecute(db, pc))
+ .then((c) => storeCoin(db, c));
}
@@ -208,7 +286,7 @@ function depleteReserve(db, reserve, mint) {
let denoms = copy(mint.keys.denoms);
let remaining = new Amount(reserve.current_amount);
denoms.sort(rankDenom);
- let workList = []
+ let workList = [];
for (let i = 0; i < 1000; i++) {
let found = false;
for (let d of denoms) {
@@ -219,7 +297,7 @@ function depleteReserve(db, reserve, mint) {
}
found = true;
remaining.sub(cost);
- workList.push([d, reserve, mint]);
+ workList.push(d);
}
if (!found) {
break;
@@ -227,17 +305,17 @@ function depleteReserve(db, reserve, mint) {
}
// Do the request one by one.
- function work(): void {
+ function next(): void {
if (workList.length == 0) {
return;
}
console.log("doing work");
- let w = workList.pop();
- withdraw(w[0], w[1], w[2])
- .then(() => work());
+ let d = workList.pop();
+ withdraw(db, d, reserve)
+ .then(() => next());
}
- work();
+ next();
}
@@ -354,7 +432,11 @@ openTalerDb().then((db) => {
"confirm-reserve": confirmReserve,
"dump-db": dumpDb
}
- return dispatch[req.type](db, req.detail, onresponse);
+ if (req.type in dispatch) {
+ return dispatch[req.type](db, req.detail, onresponse);
+ }
+ console.error(format("Request type unknown, req {0}", JSON.stringify(req)));
+ return false;
});
});