Nicer DB interface, various refactoring.
This commit is contained in:
parent
ba4d272cc4
commit
c9fc0c31ef
@ -401,7 +401,6 @@ class HashCode extends PackedArenaObject {
|
||||
case "nonce":
|
||||
qual = RandomQuality.NONCE;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
throw Error(format("unknown crypto quality: {0}", qual));
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ class Amount extends ArenaObject {
|
||||
}
|
||||
|
||||
|
||||
static getZero(currency: string, a?: Arena) {
|
||||
static getZero(currency: string, a?: Arena): Amount {
|
||||
let am = new Amount(null, a);
|
||||
let r = emsc.amount_get_zero(currency, am.getNative());
|
||||
if (r != GNUNET_OK) {
|
||||
@ -590,7 +590,6 @@ class HashCode extends PackedArenaObject {
|
||||
case "nonce":
|
||||
qual = RandomQuality.NONCE;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
throw Error(format("unknown crypto quality: {0}", qual));
|
||||
}
|
||||
|
157
extension/background/query.ts
Normal file
157
extension/background/query.ts
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/// <reference path="../decl/chrome/chrome.d.ts" />
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
function Query(db) {
|
||||
return new QueryRoot(db);
|
||||
}
|
||||
|
||||
class QueryStream {
|
||||
qr: QueryRoot;
|
||||
storeName;
|
||||
constructor(qr, storeName) {
|
||||
this.qr = qr;
|
||||
this.storeName = storeName;
|
||||
}
|
||||
join(indexName: string, key: any) {
|
||||
// join on the source relation's key, which may be
|
||||
// a path or a transformer function
|
||||
throw Error("Not implemented");
|
||||
}
|
||||
reduce(f, acc): Promise<any> {
|
||||
let leakedResolve;
|
||||
let p = new Promise((resolve, reject) => {
|
||||
leakedResolve = resolve;
|
||||
});
|
||||
let qr = this.qr;
|
||||
let storeName = this.storeName;
|
||||
|
||||
function doReduce() {
|
||||
let req = qr.tx.objectStore(storeName).openCursor();
|
||||
req.onsuccess = (e) => {
|
||||
let cursor: IDBCursorWithValue = req.result;
|
||||
if (cursor) {
|
||||
acc = f(acc, cursor.value);
|
||||
cursor.continue();
|
||||
} else {
|
||||
leakedResolve(acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.qr.work.push(doReduce);
|
||||
// We need this one level of indirection so that the kickoff
|
||||
// is run asynchronously.
|
||||
return Promise.resolve().then(() => this.qr.finish().then(() => p));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class QueryRoot {
|
||||
work = [];
|
||||
db: IDBDatabase;
|
||||
tx: IDBTransaction;
|
||||
stores = new Set();
|
||||
kickoffPromise;
|
||||
|
||||
constructor(db) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
iter(storeName): QueryStream {
|
||||
this.stores.add(storeName);
|
||||
return new QueryStream(this, storeName);
|
||||
}
|
||||
|
||||
put(storeName, val): QueryRoot {
|
||||
this.stores.add(storeName);
|
||||
function doPut() {
|
||||
this.tx.objectStore(storeName).put(val);
|
||||
}
|
||||
this.work.push(doPut);
|
||||
return this;
|
||||
}
|
||||
|
||||
putAll(storeName, iterable): QueryRoot {
|
||||
this.stores.add(storeName);
|
||||
function doPutAll() {
|
||||
for (let obj of iterable) {
|
||||
this.tx.objectStore(storeName).put(obj);
|
||||
}
|
||||
}
|
||||
this.work.push(doPutAll);
|
||||
return this;
|
||||
}
|
||||
|
||||
add(storeName, val): QueryRoot {
|
||||
this.stores.add(storeName);
|
||||
function doAdd() {
|
||||
this.tx.objectStore(storeName).add(val);
|
||||
}
|
||||
this.work.push(doAdd);
|
||||
return this;
|
||||
}
|
||||
|
||||
get(storeName, key): Promise<any> {
|
||||
this.stores.add(storeName);
|
||||
let leakedResolve;
|
||||
let p = new Promise((resolve, reject) => {
|
||||
leakedResolve = resolve;
|
||||
});
|
||||
if (!leakedResolve) {
|
||||
// According to ES6 spec (paragraph 25.4.3.1), this can't happen.
|
||||
throw Error("assertion failed");
|
||||
}
|
||||
function doGet() {
|
||||
let req = this.tx.objectStore(storeName).get(key);
|
||||
req.onsuccess = (r) => {
|
||||
leakedResolve(r);
|
||||
};
|
||||
}
|
||||
this.work.push(doGet);
|
||||
return p;
|
||||
}
|
||||
|
||||
finish(): Promise<void> {
|
||||
if (this.kickoffPromise) {
|
||||
return this.kickoffPromise;
|
||||
}
|
||||
this.kickoffPromise = new Promise((resolve, reject) => {
|
||||
|
||||
this.tx = this.db.transaction(Array.from(this.stores), "readwrite");
|
||||
this.tx.oncomplete = () => {
|
||||
resolve();
|
||||
};
|
||||
for (let w of this.work) {
|
||||
w();
|
||||
}
|
||||
});
|
||||
return this.kickoffPromise;
|
||||
}
|
||||
|
||||
delete(storeName: string, key): QueryRoot {
|
||||
this.stores.add(storeName);
|
||||
function doDelete() {
|
||||
this.tx.objectStore(storeName).delete(key);
|
||||
}
|
||||
this.work.push(doDelete);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -13,8 +13,6 @@
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/// <reference path="../decl/urijs/URIjs.d.ts" />
|
||||
/// <reference path="../decl/chrome/chrome.d.ts" />
|
||||
'use strict';
|
||||
/**
|
||||
* See http://api.taler.net/wallet.html#general
|
||||
@ -36,9 +34,7 @@ function signDeposit(db, offer, cds) {
|
||||
cds = copy(cds);
|
||||
for (let cd of cds) {
|
||||
let coinSpend;
|
||||
console.log("amount remaining:", amountRemaining.toJson());
|
||||
if (amountRemaining.value == 0 && amountRemaining.fraction == 0) {
|
||||
console.log("full amount spent");
|
||||
break;
|
||||
}
|
||||
if (amountRemaining.cmp(new Amount(cd.coin.currentAmount)) < 0) {
|
||||
@ -64,9 +60,6 @@ function signDeposit(db, offer, cds) {
|
||||
transaction_id: UInt64.fromNumber(offer.contract.transaction_id),
|
||||
};
|
||||
let d = new DepositRequestPS(args);
|
||||
console.log("Deposit request #" + ret.length);
|
||||
console.log("DepositRequestPS: \n", d.toJson());
|
||||
console.log("DepositRequestPS sig: \n", d.toPurpose().hexdump());
|
||||
let coinSig = eddsaSign(d.toPurpose(), EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
|
||||
.toCrock();
|
||||
let s = {
|
||||
@ -163,7 +156,6 @@ function getPossibleMintCoins(db, paymentAmount, depositFeeLimit, allowedMints)
|
||||
continue nextMint;
|
||||
}
|
||||
}
|
||||
console.log(format("mint {0}: acc {1} is not enough for {2}", key, JSON.stringify(accAmount.toJson()), JSON.stringify(minAmount.toJson())));
|
||||
}
|
||||
resolve(ret);
|
||||
};
|
||||
@ -173,7 +165,6 @@ function getPossibleMintCoins(db, paymentAmount, depositFeeLimit, allowedMints)
|
||||
});
|
||||
}
|
||||
function executePay(db, offer, payCoinInfo, merchantBaseUrl, chosenMint) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let payReq = {};
|
||||
payReq["H_wire"] = offer.contract.H_wire;
|
||||
payReq["H_contract"] = offer.H_contract;
|
||||
@ -189,16 +180,10 @@ function executePay(db, offer, payCoinInfo, merchantBaseUrl, chosenMint) {
|
||||
payUrl: payUrl.href(),
|
||||
payReq: payReq
|
||||
};
|
||||
let tx = db.transaction(["transactions", "coins"], "readwrite");
|
||||
tx.objectStore('transactions').put(t);
|
||||
for (let c of payCoinInfo) {
|
||||
tx.objectStore("coins").put(c.updatedCoin);
|
||||
}
|
||||
tx.oncomplete = (e) => {
|
||||
updateBadge(db);
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
return Query(db)
|
||||
.put("transactions", t)
|
||||
.putAll("coins", payCoinInfo.map((pci) => pci.updatedCoin))
|
||||
.finish();
|
||||
}
|
||||
function confirmPay(db, detail, sendResponse) {
|
||||
let offer = detail.offer;
|
||||
@ -206,37 +191,36 @@ function confirmPay(db, detail, sendResponse) {
|
||||
.then((mcs) => {
|
||||
if (Object.keys(mcs).length == 0) {
|
||||
sendResponse({ error: "Not enough coins." });
|
||||
// FIXME: does not work like expected here ...
|
||||
return;
|
||||
}
|
||||
let mintUrl = Object.keys(mcs)[0];
|
||||
let ds = signDeposit(db, offer, mcs[mintUrl]);
|
||||
return executePay(db, offer, ds, detail.merchantPageUrl, mintUrl);
|
||||
})
|
||||
return executePay(db, offer, ds, detail.merchantPageUrl, mintUrl)
|
||||
.then(() => {
|
||||
sendResponse({
|
||||
success: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
function doPayment(db, detail, sendResponse) {
|
||||
let H_contract = detail.H_contract;
|
||||
let req = db.transaction(['transactions'])
|
||||
.objectStore("transactions")
|
||||
.get(H_contract);
|
||||
console.log("executing contract", H_contract);
|
||||
req.onsuccess = (e) => {
|
||||
console.log("got db response for existing contract");
|
||||
if (!req.result) {
|
||||
Query(db)
|
||||
.get("transactions", H_contract)
|
||||
.then((r) => {
|
||||
if (!r) {
|
||||
sendResponse({ success: false, error: "contract not found" });
|
||||
return;
|
||||
}
|
||||
sendResponse({
|
||||
success: true,
|
||||
payUrl: req.result.payUrl,
|
||||
payReq: req.result.payReq
|
||||
payUrl: r.payUrl,
|
||||
payReq: r.payReq
|
||||
});
|
||||
};
|
||||
});
|
||||
// async sendResponse
|
||||
return true;
|
||||
}
|
||||
function confirmReserve(db, detail, sendResponse) {
|
||||
@ -249,7 +233,6 @@ function confirmReserve(db, detail, sendResponse) {
|
||||
form.append(detail.field_mint, detail.mint);
|
||||
// XXX: set bank-specified fields.
|
||||
let myRequest = new XMLHttpRequest();
|
||||
console.log("making request to " + detail.post_url);
|
||||
myRequest.open('post', detail.post_url);
|
||||
myRequest.send(form);
|
||||
let mintBaseUrl = canonicalizeBaseUrl(detail.mint);
|
||||
@ -336,10 +319,7 @@ function withdrawPrepare(db, denom, reserve) {
|
||||
h_denomination_pub: denomPub.encode().hash(),
|
||||
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");
|
||||
let preCoin = {
|
||||
reservePub: reservePub.toCrock(),
|
||||
blindingKey: blindingFactor.toCrock(),
|
||||
@ -351,48 +331,29 @@ function withdrawPrepare(db, denom, reserve) {
|
||||
coinEv: ev.toCrock(),
|
||||
coinValue: denom.value
|
||||
};
|
||||
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) => {
|
||||
req.onsuccess = (e) => resolve(req.result);
|
||||
});
|
||||
return Query(db).put("precoins", preCoin).finish().then(() => preCoin);
|
||||
}
|
||||
function withdrawExecute(db, pc) {
|
||||
return dbGet(db, 'reserves', pc.reservePub)
|
||||
.then((r) => new Promise((resolve, reject) => {
|
||||
console.log("loading precoin", JSON.stringify(pc));
|
||||
return Query(db)
|
||||
.get("reserves", pc.reservePub)
|
||||
.then((r) => {
|
||||
let wd = {};
|
||||
wd.denom_pub = pc.denomPub;
|
||||
wd.reserve_pub = pc.reservePub;
|
||||
wd.reserve_sig = pc.withdrawSig;
|
||||
wd.coin_ev = pc.coinEv;
|
||||
let reqUrl = URI("reserve/withdraw").absoluteTo(r.mint_base_url);
|
||||
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;
|
||||
return httpPost(reqUrl, wd);
|
||||
})
|
||||
.then(resp => {
|
||||
if (resp.status != 200) {
|
||||
throw new RequestException({
|
||||
hint: "Withdrawal failed",
|
||||
status: resp.status
|
||||
});
|
||||
}
|
||||
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 r = JSON.parse(resp.responseText);
|
||||
let denomSig = rsaUnblind(RsaSignature.fromCrock(r.ev_sig), RsaBlindingKey.fromCrock(pc.blindingKey), RsaPublicKey.fromCrock(pc.denomPub));
|
||||
let coin = {
|
||||
coinPub: pc.coinPub,
|
||||
coinPriv: pc.coinPriv,
|
||||
@ -401,43 +362,32 @@ function withdrawExecute(db, pc) {
|
||||
currentAmount: pc.coinValue,
|
||||
mintBaseUrl: pc.mintBaseUrl,
|
||||
};
|
||||
console.log("unblinded coin");
|
||||
resolve(coin);
|
||||
}
|
||||
else {
|
||||
console.log("ready state change to", myRequest.status);
|
||||
}
|
||||
return coin;
|
||||
});
|
||||
}));
|
||||
}
|
||||
function updateBadge(db) {
|
||||
let tx = db.transaction(['coins'], 'readwrite');
|
||||
let req = tx.objectStore('coins').openCursor();
|
||||
let n = 0;
|
||||
req.onsuccess = (e) => {
|
||||
let cursor = req.result;
|
||||
if (cursor) {
|
||||
let c = cursor.value;
|
||||
function countNonEmpty(n, c) {
|
||||
if (c.currentAmount.fraction != 0 || c.currentAmount.value != 0) {
|
||||
n++;
|
||||
return n + 1;
|
||||
}
|
||||
cursor.continue();
|
||||
return n;
|
||||
}
|
||||
else {
|
||||
function doBadge(n) {
|
||||
chrome.browserAction.setBadgeText({ text: "" + n });
|
||||
chrome.browserAction.setBadgeBackgroundColor({ color: "#0F0" });
|
||||
}
|
||||
};
|
||||
Query(db)
|
||||
.iter("coins")
|
||||
.reduce(countNonEmpty, 0)
|
||||
.then(doBadge);
|
||||
}
|
||||
function storeCoin(db, coin) {
|
||||
let tx = db.transaction(['coins', 'precoins'], 'readwrite');
|
||||
tx.objectStore('precoins').delete(coin.coinPub);
|
||||
tx.objectStore('coins').add(coin);
|
||||
return new Promise((resolve, reject) => {
|
||||
tx.oncomplete = (e) => {
|
||||
resolve();
|
||||
Query(db)
|
||||
.delete("precoins", coin.coinPub)
|
||||
.add("coins", coin)
|
||||
.finish()
|
||||
.then(() => {
|
||||
updateBadge(db);
|
||||
};
|
||||
});
|
||||
}
|
||||
function withdraw(db, denom, reserve) {
|
||||
@ -482,86 +432,81 @@ function depleteReserve(db, reserve, mint) {
|
||||
next();
|
||||
}
|
||||
function updateReserve(db, reservePub, mint) {
|
||||
let reserve;
|
||||
return new Promise((resolve, reject) => {
|
||||
let tx = db.transaction(['reserves']);
|
||||
tx.objectStore('reserves').get(reservePub.toCrock()).onsuccess = (e) => {
|
||||
let reserve = e.target.result;
|
||||
let reservePubStr = reservePub.toCrock();
|
||||
return Query(db)
|
||||
.get("reserves", reservePubStr)
|
||||
.then((reserve) => {
|
||||
let reqUrl = URI("reserve/status").absoluteTo(mint.baseUrl);
|
||||
reqUrl.query({ 'reserve_pub': reservePub.toCrock() });
|
||||
let myRequest = new XMLHttpRequest();
|
||||
console.log("making request to " + reqUrl.href());
|
||||
myRequest.open('get', reqUrl.href());
|
||||
myRequest.send();
|
||||
myRequest.addEventListener('readystatechange', (e) => {
|
||||
if (myRequest.readyState == XMLHttpRequest.DONE) {
|
||||
if (myRequest.status != 200) {
|
||||
reject();
|
||||
return;
|
||||
reqUrl.query({ 'reserve_pub': reservePubStr });
|
||||
return httpGet(reqUrl).then(resp => {
|
||||
if (resp.status != 200) {
|
||||
throw Error();
|
||||
}
|
||||
let reserveInfo = JSON.parse(resp.responseText);
|
||||
if (!reserveInfo) {
|
||||
throw Error();
|
||||
}
|
||||
let reserveInfo = JSON.parse(myRequest.responseText);
|
||||
console.log("got response " + JSON.stringify(reserveInfo));
|
||||
reserve.current_amount = reserveInfo.balance;
|
||||
let tx = db.transaction(['reserves'], 'readwrite');
|
||||
console.log("putting updated reserve " + JSON.stringify(reserve));
|
||||
tx.objectStore('reserves').put(reserve);
|
||||
tx.oncomplete = (e) => {
|
||||
resolve(reserve);
|
||||
let q = Query(db);
|
||||
return q.put("reserves", reserve).finish().then(() => reserve);
|
||||
});
|
||||
});
|
||||
}
|
||||
function httpReq(method, url, options) {
|
||||
let urlString;
|
||||
if (url instanceof URI) {
|
||||
urlString = url.href();
|
||||
}
|
||||
else if (typeof url === "string") {
|
||||
urlString = url;
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
let myRequest = new XMLHttpRequest();
|
||||
myRequest.open(method, urlString);
|
||||
if (options && options.req) {
|
||||
myRequest.send(options.req);
|
||||
}
|
||||
myRequest.addEventListener("readystatechange", (e) => {
|
||||
if (myRequest.readyState == XMLHttpRequest.DONE) {
|
||||
let resp = {
|
||||
status: myRequest.status,
|
||||
responseText: myRequest.responseText
|
||||
};
|
||||
resolve(resp);
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
function httpGet(url) {
|
||||
return httpReq("get", url);
|
||||
}
|
||||
function httpPost(url, body) {
|
||||
return httpReq("put", url, { req: JSON.stringify(body) });
|
||||
}
|
||||
class RequestException {
|
||||
constructor(detail) {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Update or add mint DB entry by fetching the /keys information.
|
||||
* Optionally link the reserve entry to the new or existing
|
||||
* mint entry in then DB.
|
||||
*/
|
||||
function updateMintFromUrl(db, baseUrl) {
|
||||
console.log("base url is " + baseUrl);
|
||||
let reqUrl = URI("keys").absoluteTo(baseUrl);
|
||||
let myRequest = new XMLHttpRequest();
|
||||
myRequest.open('get', reqUrl.href());
|
||||
myRequest.send();
|
||||
return new Promise((resolve, reject) => {
|
||||
myRequest.addEventListener('readystatechange', (e) => {
|
||||
console.log("state change to " + myRequest.readyState);
|
||||
if (myRequest.readyState == XMLHttpRequest.DONE) {
|
||||
if (myRequest.status == 200) {
|
||||
console.log("got /keys");
|
||||
let mintKeysJson = JSON.parse(myRequest.responseText);
|
||||
if (!mintKeysJson) {
|
||||
console.log("keys invalid");
|
||||
reject();
|
||||
return httpGet(reqUrl).then((resp) => {
|
||||
if (resp.status != 200) {
|
||||
throw Error("/keys request failed");
|
||||
}
|
||||
let mintKeysJson = JSON.parse(resp.responseText);
|
||||
if (!mintKeysJson) {
|
||||
throw new RequestException({ url: reqUrl, hint: "keys invalid" });
|
||||
}
|
||||
else {
|
||||
let mint = {
|
||||
baseUrl: baseUrl,
|
||||
keys: mintKeysJson
|
||||
};
|
||||
let tx = db.transaction(['mints', 'denoms'], 'readwrite');
|
||||
tx.objectStore('mints').put(mint);
|
||||
for (let d of mintKeysJson.denoms) {
|
||||
// TODO: verify and complete
|
||||
let di = {
|
||||
denomPub: d.denom_pub,
|
||||
value: d.value
|
||||
};
|
||||
tx.objectStore('denoms').put(di);
|
||||
}
|
||||
tx.oncomplete = (e) => {
|
||||
resolve(mint);
|
||||
};
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log("/keys request failed with status " + myRequest.status);
|
||||
// XXX: also write last error to DB to show in the UI
|
||||
reject();
|
||||
}
|
||||
}
|
||||
});
|
||||
return Query(db).put("mints", mint).finish().then(() => mint);
|
||||
});
|
||||
}
|
||||
function dumpDb(db, detail, sendResponse) {
|
||||
@ -570,7 +515,6 @@ function dumpDb(db, detail, sendResponse) {
|
||||
version: db.version,
|
||||
stores: {}
|
||||
};
|
||||
console.log("stores: " + JSON.stringify(db.objectStoreNames));
|
||||
let tx = db.transaction(db.objectStoreNames);
|
||||
tx.addEventListener('complete', (e) => {
|
||||
sendResponse(dump);
|
||||
@ -600,38 +544,28 @@ function reset(db, detail, sendResponse) {
|
||||
indexedDB.deleteDatabase(DB_NAME);
|
||||
chrome.browserAction.setBadgeText({ text: "" });
|
||||
console.log("reset done");
|
||||
// Response is synchronous
|
||||
return false;
|
||||
}
|
||||
function balances(db, detail, sendResponse) {
|
||||
let byCurrency = {};
|
||||
let tx = db.transaction(['coins', 'denoms']);
|
||||
let req = tx.objectStore('coins').openCursor();
|
||||
req.onsuccess = (e) => {
|
||||
let cursor = req.result;
|
||||
if (cursor) {
|
||||
let c = cursor.value;
|
||||
tx.objectStore('denoms').get(c.denomPub).onsuccess = (e2) => {
|
||||
let d = e2.target.result;
|
||||
let acc = byCurrency[d.value.currency];
|
||||
function collectBalances(c, byCurrency) {
|
||||
let acc = byCurrency[c.currentAmount.currency];
|
||||
if (!acc) {
|
||||
acc = Amount.getZero(c.currentAmount.currency);
|
||||
acc = Amount.getZero(c.currentAmount.currency).toJson();
|
||||
}
|
||||
let am = new Amount(c.currentAmount);
|
||||
am.add(new Amount(acc));
|
||||
byCurrency[d.value.currency] = am.toJson();
|
||||
console.log("counting", byCurrency[d.value.currency]);
|
||||
};
|
||||
cursor.continue();
|
||||
byCurrency[c.currentAmount.currency] = am.toJson();
|
||||
}
|
||||
else {
|
||||
sendResponse(byCurrency);
|
||||
}
|
||||
};
|
||||
Query(db)
|
||||
.iter("coins")
|
||||
.reduce(collectBalances, {})
|
||||
.then(sendResponse);
|
||||
return true;
|
||||
}
|
||||
chrome.browserAction.setBadgeText({ text: "" });
|
||||
openTalerDb().then((db) => {
|
||||
console.log("db loaded");
|
||||
function wxMain() {
|
||||
chrome.browserAction.setBadgeText({ text: "" });
|
||||
openTalerDb().then((db) => {
|
||||
updateBadge(db);
|
||||
chrome.runtime.onMessage.addListener(function (req, sender, onresponse) {
|
||||
let dispatch = {
|
||||
@ -648,4 +582,6 @@ openTalerDb().then((db) => {
|
||||
console.error(format("Request type {1} unknown, req {0}", JSON.stringify(req), req.type));
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
wxMain();
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
/// <reference path="../decl/urijs/URIjs.d.ts" />
|
||||
/// <reference path="../decl/chrome/chrome.d.ts" />
|
||||
import URIStatic = uri.URIStatic;
|
||||
import Request = chrome.devtools.network.Request;
|
||||
'use strict';
|
||||
|
||||
|
||||
@ -25,22 +27,6 @@ interface AmountJson {
|
||||
currency: string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See http://api.taler.net/wallet.html#general
|
||||
*/
|
||||
function canonicalizeBaseUrl(url) {
|
||||
let x = new URI(url);
|
||||
if (!x.protocol()) {
|
||||
x.protocol("https");
|
||||
}
|
||||
x.path(x.path() + "/").normalizePath();
|
||||
x.fragment();
|
||||
x.query();
|
||||
return x.href()
|
||||
}
|
||||
|
||||
|
||||
interface ConfirmPayRequest {
|
||||
merchantPageUrl: string;
|
||||
offer: Offer;
|
||||
@ -50,6 +36,12 @@ interface MintCoins {
|
||||
[mintUrl: string]: Db.CoinWithDenom[];
|
||||
}
|
||||
|
||||
|
||||
interface MintInfo {
|
||||
master_pub: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface Offer {
|
||||
contract: Contract;
|
||||
sig: string;
|
||||
@ -74,7 +66,6 @@ interface Contract {
|
||||
transaction_id: number;
|
||||
}
|
||||
|
||||
|
||||
interface CoinPaySig {
|
||||
coin_sig: string;
|
||||
coin_pub: string;
|
||||
@ -84,9 +75,39 @@ interface CoinPaySig {
|
||||
}
|
||||
|
||||
|
||||
interface Transaction {
|
||||
contractHash: string;
|
||||
contract: any;
|
||||
payUrl: string;
|
||||
payReq: any;
|
||||
}
|
||||
|
||||
|
||||
interface Reserve {
|
||||
mint_base_url: string
|
||||
reserve_priv: string;
|
||||
reserve_pub: string;
|
||||
}
|
||||
|
||||
|
||||
type PayCoinInfo = Array<{ updatedCoin: Db.Coin, sig: CoinPaySig }>;
|
||||
|
||||
|
||||
/**
|
||||
* See http://api.taler.net/wallet.html#general
|
||||
*/
|
||||
function canonicalizeBaseUrl(url) {
|
||||
let x = new URI(url);
|
||||
if (!x.protocol()) {
|
||||
x.protocol("https");
|
||||
}
|
||||
x.path(x.path() + "/").normalizePath();
|
||||
x.fragment();
|
||||
x.query();
|
||||
return x.href()
|
||||
}
|
||||
|
||||
|
||||
function signDeposit(db: IDBDatabase,
|
||||
offer: Offer,
|
||||
cds: Db.CoinWithDenom[]): PayCoinInfo {
|
||||
@ -97,10 +118,7 @@ function signDeposit(db: IDBDatabase,
|
||||
for (let cd of cds) {
|
||||
let coinSpend;
|
||||
|
||||
console.log("amount remaining:", amountRemaining.toJson());
|
||||
|
||||
if (amountRemaining.value == 0 && amountRemaining.fraction == 0) {
|
||||
console.log("full amount spent");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -131,10 +149,6 @@ function signDeposit(db: IDBDatabase,
|
||||
|
||||
let d = new DepositRequestPS(args);
|
||||
|
||||
console.log("Deposit request #" + ret.length);
|
||||
console.log("DepositRequestPS: \n", d.toJson());
|
||||
console.log("DepositRequestPS sig: \n", d.toPurpose().hexdump());
|
||||
|
||||
let coinSig = eddsaSign(d.toPurpose(),
|
||||
EddsaPrivateKey.fromCrock(cd.coin.coinPriv))
|
||||
.toCrock();
|
||||
@ -151,11 +165,6 @@ function signDeposit(db: IDBDatabase,
|
||||
return ret;
|
||||
}
|
||||
|
||||
interface MintInfo {
|
||||
master_pub: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get mints and associated coins that are still spendable,
|
||||
@ -246,10 +255,6 @@ function getPossibleMintCoins(db: IDBDatabase,
|
||||
continue nextMint;
|
||||
}
|
||||
}
|
||||
console.log(format("mint {0}: acc {1} is not enough for {2}",
|
||||
key,
|
||||
JSON.stringify(accAmount.toJson()),
|
||||
JSON.stringify(minAmount.toJson())));
|
||||
}
|
||||
resolve(ret);
|
||||
};
|
||||
@ -261,20 +266,11 @@ function getPossibleMintCoins(db: IDBDatabase,
|
||||
}
|
||||
|
||||
|
||||
interface Transaction {
|
||||
contractHash: string;
|
||||
contract: any;
|
||||
payUrl: string;
|
||||
payReq: any;
|
||||
}
|
||||
|
||||
|
||||
function executePay(db,
|
||||
offer: Offer,
|
||||
payCoinInfo: PayCoinInfo,
|
||||
merchantBaseUrl: string,
|
||||
chosenMint: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
chosenMint: string): Promise<void> {
|
||||
let payReq = {};
|
||||
payReq["H_wire"] = offer.contract.H_wire;
|
||||
payReq["H_contract"] = offer.H_contract;
|
||||
@ -290,16 +286,11 @@ function executePay(db,
|
||||
payUrl: payUrl.href(),
|
||||
payReq: payReq
|
||||
};
|
||||
let tx = db.transaction(["transactions", "coins"], "readwrite");
|
||||
tx.objectStore('transactions').put(t);
|
||||
for (let c of payCoinInfo) {
|
||||
tx.objectStore("coins").put(c.updatedCoin);
|
||||
}
|
||||
tx.oncomplete = (e) => {
|
||||
updateBadge(db);
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
|
||||
return Query(db)
|
||||
.put("transactions", t)
|
||||
.putAll("coins", payCoinInfo.map((pci) => pci.updatedCoin))
|
||||
.finish();
|
||||
}
|
||||
|
||||
|
||||
@ -312,39 +303,38 @@ function confirmPay(db, detail: ConfirmPayRequest, sendResponse) {
|
||||
.then((mcs) => {
|
||||
if (Object.keys(mcs).length == 0) {
|
||||
sendResponse({error: "Not enough coins."});
|
||||
// FIXME: does not work like expected here ...
|
||||
return;
|
||||
}
|
||||
let mintUrl = Object.keys(mcs)[0];
|
||||
let ds = signDeposit(db, offer, mcs[mintUrl]);
|
||||
return executePay(db, offer, ds, detail.merchantPageUrl, mintUrl);
|
||||
})
|
||||
return executePay(db, offer, ds, detail.merchantPageUrl, mintUrl)
|
||||
.then(() => {
|
||||
sendResponse({
|
||||
success: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function doPayment(db, detail, sendResponse) {
|
||||
let H_contract = detail.H_contract;
|
||||
let req = db.transaction(['transactions'])
|
||||
.objectStore("transactions")
|
||||
.get(H_contract);
|
||||
console.log("executing contract", H_contract);
|
||||
req.onsuccess = (e) => {
|
||||
console.log("got db response for existing contract");
|
||||
if (!req.result) {
|
||||
Query(db)
|
||||
.get("transactions", H_contract)
|
||||
.then((r) => {
|
||||
if (!r) {
|
||||
sendResponse({success: false, error: "contract not found"});
|
||||
return;
|
||||
}
|
||||
sendResponse({
|
||||
success: true,
|
||||
payUrl: req.result.payUrl,
|
||||
payReq: req.result.payReq
|
||||
payUrl: r.payUrl,
|
||||
payReq: r.payReq
|
||||
});
|
||||
};
|
||||
});
|
||||
// async sendResponse
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -359,7 +349,6 @@ function confirmReserve(db, detail, sendResponse) {
|
||||
form.append(detail.field_mint, detail.mint);
|
||||
// XXX: set bank-specified fields.
|
||||
let myRequest = new XMLHttpRequest();
|
||||
console.log("making request to " + detail.post_url);
|
||||
myRequest.open('post', detail.post_url);
|
||||
myRequest.send(form);
|
||||
let mintBaseUrl = canonicalizeBaseUrl(detail.mint);
|
||||
@ -427,13 +416,6 @@ function rankDenom(denom1: any, denom2: any) {
|
||||
}
|
||||
|
||||
|
||||
interface Reserve {
|
||||
mint_base_url: string
|
||||
reserve_priv: string;
|
||||
reserve_pub: string;
|
||||
}
|
||||
|
||||
|
||||
function withdrawPrepare(db: IDBDatabase,
|
||||
denom: Db.Denomination,
|
||||
reserve: Reserve): Promise<Db.PreCoin> {
|
||||
@ -465,11 +447,7 @@ function withdrawPrepare(db: IDBDatabase,
|
||||
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");
|
||||
|
||||
let preCoin: Db.PreCoin = {
|
||||
reservePub: reservePub.toCrock(),
|
||||
@ -483,54 +461,31 @@ function withdrawPrepare(db: IDBDatabase,
|
||||
coinValue: denom.value
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
return Query(db).put("precoins", preCoin).finish().then(() => preCoin);
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
return Query(db)
|
||||
.get("reserves", pc.reservePub)
|
||||
.then((r) => {
|
||||
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;
|
||||
return httpPost(reqUrl, wd);
|
||||
})
|
||||
.then(resp => {
|
||||
if (resp.status != 200) {
|
||||
throw new RequestException({
|
||||
hint: "Withdrawal failed",
|
||||
status: resp.status
|
||||
});
|
||||
}
|
||||
console.log("Withdrawal successful");
|
||||
console.log(myRequest.responseText);
|
||||
let resp = JSON.parse(myRequest.responseText);
|
||||
let denomSig = rsaUnblind(RsaSignature.fromCrock(resp.ev_sig),
|
||||
let r = JSON.parse(resp.responseText);
|
||||
let denomSig = rsaUnblind(RsaSignature.fromCrock(r.ev_sig),
|
||||
RsaBlindingKey.fromCrock(pc.blindingKey),
|
||||
RsaPublicKey.fromCrock(pc.denomPub));
|
||||
let coin: Db.Coin = {
|
||||
@ -541,45 +496,38 @@ function withdrawExecute(db, pc: Db.PreCoin): Promise<Db.Coin> {
|
||||
currentAmount: pc.coinValue,
|
||||
mintBaseUrl: pc.mintBaseUrl,
|
||||
};
|
||||
console.log("unblinded coin");
|
||||
resolve(coin);
|
||||
} else {
|
||||
console.log("ready state change to", myRequest.status);
|
||||
}
|
||||
return coin;
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
function updateBadge(db) {
|
||||
let tx = db.transaction(['coins'], 'readwrite');
|
||||
let req = tx.objectStore('coins').openCursor();
|
||||
let n = 0;
|
||||
req.onsuccess = (e) => {
|
||||
let cursor = req.result;
|
||||
if (cursor) {
|
||||
let c: Db.Coin = cursor.value;
|
||||
function countNonEmpty(n, c) {
|
||||
if (c.currentAmount.fraction != 0 || c.currentAmount.value != 0) {
|
||||
n++;
|
||||
return n + 1;
|
||||
}
|
||||
cursor.continue();
|
||||
} else {
|
||||
return n;
|
||||
}
|
||||
|
||||
function doBadge(n) {
|
||||
chrome.browserAction.setBadgeText({text: "" + n});
|
||||
chrome.browserAction.setBadgeBackgroundColor({color: "#0F0"});
|
||||
}
|
||||
}
|
||||
|
||||
Query(db)
|
||||
.iter("coins")
|
||||
.reduce(countNonEmpty, 0)
|
||||
.then(doBadge);
|
||||
}
|
||||
|
||||
|
||||
function storeCoin(db, coin: Db.Coin) {
|
||||
let tx = db.transaction(['coins', 'precoins'], 'readwrite');
|
||||
tx.objectStore('precoins').delete(coin.coinPub);
|
||||
tx.objectStore('coins').add(coin);
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
tx.oncomplete = (e) => {
|
||||
resolve();
|
||||
Query(db)
|
||||
.delete("precoins", coin.coinPub)
|
||||
.add("coins", coin)
|
||||
.finish()
|
||||
.then(() => {
|
||||
updateBadge(db);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -631,88 +579,102 @@ function depleteReserve(db, reserve, mint) {
|
||||
}
|
||||
|
||||
|
||||
function updateReserve(db, reservePub: EddsaPublicKey, mint) {
|
||||
let reserve;
|
||||
return new Promise((resolve, reject) => {
|
||||
let tx = db.transaction(['reserves']);
|
||||
tx.objectStore('reserves').get(reservePub.toCrock()).onsuccess = (e) => {
|
||||
let reserve = e.target.result;
|
||||
function updateReserve(db: IDBDatabase,
|
||||
reservePub: EddsaPublicKey,
|
||||
mint): Promise<Reserve> {
|
||||
let reservePubStr = reservePub.toCrock();
|
||||
return Query(db)
|
||||
.get("reserves", reservePubStr)
|
||||
.then((reserve) => {
|
||||
let reqUrl = URI("reserve/status").absoluteTo(mint.baseUrl);
|
||||
reqUrl.query({'reserve_pub': reservePub.toCrock()});
|
||||
let myRequest = new XMLHttpRequest();
|
||||
console.log("making request to " + reqUrl.href());
|
||||
myRequest.open('get', reqUrl.href());
|
||||
myRequest.send();
|
||||
myRequest.addEventListener('readystatechange', (e) => {
|
||||
if (myRequest.readyState == XMLHttpRequest.DONE) {
|
||||
if (myRequest.status != 200) {
|
||||
reject();
|
||||
return;
|
||||
reqUrl.query({'reserve_pub': reservePubStr});
|
||||
return httpGet(reqUrl).then(resp => {
|
||||
if (resp.status != 200) {
|
||||
throw Error();
|
||||
}
|
||||
let reserveInfo = JSON.parse(resp.responseText);
|
||||
if (!reserveInfo) {
|
||||
throw Error();
|
||||
}
|
||||
let reserveInfo = JSON.parse(myRequest.responseText);
|
||||
console.log("got response " + JSON.stringify(reserveInfo));
|
||||
reserve.current_amount = reserveInfo.balance;
|
||||
let tx = db.transaction(['reserves'], 'readwrite');
|
||||
console.log("putting updated reserve " + JSON.stringify(reserve));
|
||||
tx.objectStore('reserves').put(reserve);
|
||||
tx.oncomplete = (e) => {
|
||||
resolve(reserve);
|
||||
};
|
||||
}
|
||||
let q = Query(db);
|
||||
return q.put("reserves", reserve).finish().then(() => reserve);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
interface HttpResponse {
|
||||
status: number;
|
||||
responseText: string;
|
||||
}
|
||||
|
||||
|
||||
function httpReq(method: string,
|
||||
url: string|uri.URI,
|
||||
options?: any): Promise<HttpResponse> {
|
||||
let urlString: string;
|
||||
if (url instanceof URI) {
|
||||
urlString = url.href();
|
||||
} else if (typeof url === "string") {
|
||||
urlString = url;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let myRequest = new XMLHttpRequest();
|
||||
myRequest.open(method, urlString);
|
||||
if (options && options.req) {
|
||||
myRequest.send(options.req);
|
||||
}
|
||||
myRequest.addEventListener("readystatechange", (e) => {
|
||||
if (myRequest.readyState == XMLHttpRequest.DONE) {
|
||||
let resp = {
|
||||
status: myRequest.status,
|
||||
responseText: myRequest.responseText
|
||||
};
|
||||
resolve(resp);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function httpGet(url: string|uri.URI) {
|
||||
return httpReq("get", url);
|
||||
}
|
||||
|
||||
|
||||
function httpPost(url: string|uri.URI, body) {
|
||||
return httpReq("put", url, {req: JSON.stringify(body)});
|
||||
}
|
||||
|
||||
|
||||
class RequestException {
|
||||
constructor(detail) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update or add mint DB entry by fetching the /keys information.
|
||||
* Optionally link the reserve entry to the new or existing
|
||||
* mint entry in then DB.
|
||||
*/
|
||||
function updateMintFromUrl(db, baseUrl) {
|
||||
console.log("base url is " + baseUrl);
|
||||
let reqUrl = URI("keys").absoluteTo(baseUrl);
|
||||
let myRequest = new XMLHttpRequest();
|
||||
myRequest.open('get', reqUrl.href());
|
||||
myRequest.send();
|
||||
return new Promise((resolve, reject) => {
|
||||
myRequest.addEventListener('readystatechange', (e) => {
|
||||
console.log("state change to " + myRequest.readyState);
|
||||
if (myRequest.readyState == XMLHttpRequest.DONE) {
|
||||
if (myRequest.status == 200) {
|
||||
console.log("got /keys");
|
||||
let mintKeysJson = JSON.parse(myRequest.responseText);
|
||||
return httpGet(reqUrl).then((resp) => {
|
||||
if (resp.status != 200) {
|
||||
throw Error("/keys request failed");
|
||||
}
|
||||
let mintKeysJson = JSON.parse(resp.responseText);
|
||||
if (!mintKeysJson) {
|
||||
console.log("keys invalid");
|
||||
reject();
|
||||
} else {
|
||||
throw new RequestException({url: reqUrl, hint: "keys invalid"});
|
||||
}
|
||||
let mint: Db.Mint = {
|
||||
baseUrl: baseUrl,
|
||||
keys: mintKeysJson
|
||||
};
|
||||
let tx = db.transaction(['mints', 'denoms'], 'readwrite');
|
||||
tx.objectStore('mints').put(mint);
|
||||
for (let d of mintKeysJson.denoms) {
|
||||
// TODO: verify and complete
|
||||
let di = {
|
||||
denomPub: d.denom_pub,
|
||||
value: d.value
|
||||
};
|
||||
tx.objectStore('denoms').put(di);
|
||||
}
|
||||
tx.oncomplete = (e) => {
|
||||
resolve(mint);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
console.log("/keys request failed with status " + myRequest.status);
|
||||
// XXX: also write last error to DB to show in the UI
|
||||
reject();
|
||||
}
|
||||
}
|
||||
});
|
||||
return Query(db).put("mints", mint).finish().then(() => mint);
|
||||
});
|
||||
}
|
||||
|
||||
@ -723,7 +685,6 @@ function dumpDb(db, detail, sendResponse) {
|
||||
version: db.version,
|
||||
stores: {}
|
||||
};
|
||||
console.log("stores: " + JSON.stringify(db.objectStoreNames));
|
||||
let tx = db.transaction(db.objectStoreNames);
|
||||
tx.addEventListener('complete', (e) => {
|
||||
sendResponse(dump);
|
||||
@ -755,41 +716,34 @@ function reset(db, detail, sendResponse) {
|
||||
indexedDB.deleteDatabase(DB_NAME);
|
||||
chrome.browserAction.setBadgeText({text: ""});
|
||||
console.log("reset done");
|
||||
// Response is synchronous
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function balances(db, detail, sendResponse) {
|
||||
let byCurrency = {};
|
||||
let tx = db.transaction(['coins', 'denoms']);
|
||||
let req = tx.objectStore('coins').openCursor();
|
||||
req.onsuccess = (e) => {
|
||||
let cursor = req.result;
|
||||
if (cursor) {
|
||||
let c: Db.Coin = cursor.value;
|
||||
tx.objectStore('denoms').get(c.denomPub).onsuccess = (e2) => {
|
||||
let d = e2.target.result;
|
||||
let acc = byCurrency[d.value.currency];
|
||||
function balances(db, detail, sendResponse): boolean {
|
||||
function collectBalances(c: Db.Coin, byCurrency) {
|
||||
let acc: AmountJson = byCurrency[c.currentAmount.currency];
|
||||
if (!acc) {
|
||||
acc = Amount.getZero(c.currentAmount.currency);
|
||||
acc = Amount.getZero(c.currentAmount.currency).toJson();
|
||||
}
|
||||
let am = new Amount(c.currentAmount);
|
||||
am.add(new Amount(acc));
|
||||
byCurrency[d.value.currency] = am.toJson();
|
||||
console.log("counting", byCurrency[d.value.currency]);
|
||||
};
|
||||
cursor.continue();
|
||||
} else {
|
||||
sendResponse(byCurrency);
|
||||
byCurrency[c.currentAmount.currency] = am.toJson();
|
||||
}
|
||||
};
|
||||
|
||||
Query(db)
|
||||
.iter("coins")
|
||||
.reduce(collectBalances, {})
|
||||
.then(sendResponse);
|
||||
return true;
|
||||
}
|
||||
|
||||
chrome.browserAction.setBadgeText({text: ""});
|
||||
|
||||
openTalerDb().then((db) => {
|
||||
console.log("db loaded");
|
||||
function wxMain() {
|
||||
chrome.browserAction.setBadgeText({text: ""});
|
||||
|
||||
openTalerDb().then((db) => {
|
||||
updateBadge(db);
|
||||
chrome.runtime.onMessage.addListener(
|
||||
function(req, sender, onresponse) {
|
||||
@ -809,4 +763,8 @@ openTalerDb().then((db) => {
|
||||
req.type));
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
wxMain();
|
@ -46,6 +46,7 @@
|
||||
"background/libwrapper.js",
|
||||
"background/emscriptif.js",
|
||||
"background/db.js",
|
||||
"background/query.js",
|
||||
"background/wallet.js"
|
||||
]
|
||||
},
|
||||
|
@ -7,6 +7,7 @@
|
||||
"background/wallet.ts",
|
||||
"background/emscriptif.ts",
|
||||
"background/db.ts",
|
||||
"background/query.ts",
|
||||
"lib/util.ts",
|
||||
"lib/polyfill-react.ts",
|
||||
"content_scripts/notify.ts",
|
||||
|
Loading…
Reference in New Issue
Block a user