aboutsummaryrefslogtreecommitdiff
path: root/src/wxBackend.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/wxBackend.ts')
-rw-r--r--src/wxBackend.ts263
1 files changed, 134 insertions, 129 deletions
diff --git a/src/wxBackend.ts b/src/wxBackend.ts
index 26020c7fe..6b9601572 100644
--- a/src/wxBackend.ts
+++ b/src/wxBackend.ts
@@ -24,6 +24,20 @@
/**
* Imports.
*/
+import { Checkable } from "./checkable";
+import { ChromeBadge } from "./chromeBadge";
+import { BrowserHttpLib } from "./http";
+import * as logging from "./logging";
+import {
+ Index,
+ Store,
+} from "./query";
+import {
+ AmountJson,
+ Contract,
+ Notifier,
+} from "./types";
+import URI = require("urijs");
import {
Badge,
ConfirmReserveRequest,
@@ -32,19 +46,8 @@ import {
Stores,
Wallet,
} from "./wallet";
-import {
- AmountJson,
- Contract,
- Notifier,
-} from "./types";
-import MessageSender = chrome.runtime.MessageSender;
-import { ChromeBadge } from "./chromeBadge";
-import * as logging from "./logging";
-import { Store, Index } from "./query";
-import { BrowserHttpLib } from "./http";
-import { Checkable } from "./checkable";
import Port = chrome.runtime.Port;
-import URI = require("urijs");
+import MessageSender = chrome.runtime.MessageSender;
const DB_NAME = "taler";
@@ -60,32 +63,33 @@ const DB_VERSION = 17;
type Handler = (detail: any, sender: MessageSender) => Promise<any>;
function makeHandlers(db: IDBDatabase,
- wallet: Wallet): { [msg: string]: Handler } {
+ wallet: Wallet): { [msg: string]: Handler } {
return {
- ["balances"]: function (detail, sender) {
+ ["balances"]: (detail, sender) => {
return wallet.getBalances();
},
- ["dump-db"]: function (detail, sender) {
+ ["dump-db"]: (detail, sender) => {
return exportDb(db);
},
- ["import-db"]: function (detail, sender) {
+ ["import-db"]: (detail, sender) => {
return importDb(db, detail.dump);
},
- ["get-tab-cookie"]: function (detail, sender) {
+ ["get-tab-cookie"]: (detail, sender) => {
if (!sender || !sender.tab || !sender.tab.id) {
return Promise.resolve();
}
- let id: number = sender.tab.id;
- let info: any = <any> paymentRequestCookies[id];
+ const id: number = sender.tab.id;
+ const info: any = paymentRequestCookies[id] as any;
delete paymentRequestCookies[id];
return Promise.resolve(info);
},
- ["ping"]: function (detail, sender) {
+ ["ping"]: (detail, sender) => {
return Promise.resolve();
},
- ["reset"]: function (detail, sender) {
+ ["reset"]: (detail, sender) => {
if (db) {
- let tx = db.transaction(Array.from(db.objectStoreNames), 'readwrite');
+ const tx = db.transaction(Array.from(db.objectStoreNames), "readwrite");
+ // tslint:disable-next-line:prefer-for-of
for (let i = 0; i < db.objectStoreNames.length; i++) {
tx.objectStore(db.objectStoreNames[i]).clear();
}
@@ -97,15 +101,15 @@ function makeHandlers(db: IDBDatabase,
// Response is synchronous
return Promise.resolve({});
},
- ["create-reserve"]: function (detail, sender) {
+ ["create-reserve"]: (detail, sender) => {
const d = {
- exchange: detail.exchange,
amount: detail.amount,
+ exchange: detail.exchange,
};
const req = CreateReserveRequest.checked(d);
return wallet.createReserve(req);
},
- ["confirm-reserve"]: function (detail, sender) {
+ ["confirm-reserve"]: (detail, sender) => {
// TODO: make it a checkable
const d = {
reservePub: detail.reservePub,
@@ -113,10 +117,10 @@ function makeHandlers(db: IDBDatabase,
const req = ConfirmReserveRequest.checked(d);
return wallet.confirmReserve(req);
},
- ["generate-nonce"]: function (detail, sender) {
+ ["generate-nonce"]: (detail, sender) => {
return wallet.generateNonce();
},
- ["confirm-pay"]: function (detail, sender) {
+ ["confirm-pay"]: (detail, sender) => {
let offer: OfferRecord;
try {
offer = OfferRecord.checked(detail.offer);
@@ -124,9 +128,9 @@ function makeHandlers(db: IDBDatabase,
if (e instanceof Checkable.SchemaError) {
console.error("schema error:", e.message);
return Promise.resolve({
+ detail,
error: "invalid contract",
hint: e.message,
- detail: detail,
});
} else {
throw e;
@@ -135,7 +139,7 @@ function makeHandlers(db: IDBDatabase,
return wallet.confirmPay(offer);
},
- ["check-pay"]: function (detail, sender) {
+ ["check-pay"]: (detail, sender) => {
let offer: OfferRecord;
try {
offer = OfferRecord.checked(detail.offer);
@@ -143,9 +147,9 @@ function makeHandlers(db: IDBDatabase,
if (e instanceof Checkable.SchemaError) {
console.error("schema error:", e.message);
return Promise.resolve({
+ detail,
error: "invalid contract",
hint: e.message,
- detail: detail,
});
} else {
throw e;
@@ -153,34 +157,34 @@ function makeHandlers(db: IDBDatabase,
}
return wallet.checkPay(offer);
},
- ["query-payment"]: function (detail: any, sender: MessageSender) {
+ ["query-payment"]: (detail: any, sender: MessageSender) => {
if (sender.tab && sender.tab.id) {
rateLimitCache[sender.tab.id]++;
if (rateLimitCache[sender.tab.id] > 10) {
console.warn("rate limit for query-payment exceeded");
- let msg = {
+ const msg = {
error: "rate limit exceeded for query-payment",
- rateLimitExceeded: true,
hint: "Check for redirect loops",
+ rateLimitExceeded: true,
};
return Promise.resolve(msg);
}
}
return wallet.queryPayment(detail.url);
},
- ["exchange-info"]: function (detail) {
+ ["exchange-info"]: (detail) => {
if (!detail.baseUrl) {
return Promise.resolve({ error: "bad url" });
}
return wallet.updateExchangeFromUrl(detail.baseUrl);
},
- ["currency-info"]: function (detail) {
+ ["currency-info"]: (detail) => {
if (!detail.name) {
return Promise.resolve({ error: "name missing" });
}
return wallet.getCurrencyRecord(detail.name);
},
- ["hash-contract"]: function (detail) {
+ ["hash-contract"]: (detail) => {
if (!detail.contract) {
return Promise.resolve({ error: "contract missing" });
}
@@ -188,91 +192,91 @@ function makeHandlers(db: IDBDatabase,
return { hash };
});
},
- ["put-history-entry"]: function (detail: any) {
+ ["put-history-entry"]: (detail: any) => {
if (!detail.historyEntry) {
return Promise.resolve({ error: "historyEntry missing" });
}
return wallet.putHistory(detail.historyEntry);
},
- ["save-offer"]: function (detail: any) {
- let offer = detail.offer;
+ ["save-offer"]: (detail: any) => {
+ const offer = detail.offer;
if (!offer) {
return Promise.resolve({ error: "offer missing" });
}
console.log("handling safe-offer", detail);
// FIXME: fully migrate to new terminology
- let checkedOffer = OfferRecord.checked(offer);
+ const checkedOffer = OfferRecord.checked(offer);
return wallet.saveOffer(checkedOffer);
},
- ["reserve-creation-info"]: function (detail, sender) {
+ ["reserve-creation-info"]: (detail, sender) => {
if (!detail.baseUrl || typeof detail.baseUrl !== "string") {
return Promise.resolve({ error: "bad url" });
}
- let amount = AmountJson.checked(detail.amount);
+ const amount = AmountJson.checked(detail.amount);
return wallet.getReserveCreationInfo(detail.baseUrl, amount);
},
- ["get-history"]: function (detail, sender) {
+ ["get-history"]: (detail, sender) => {
// TODO: limit history length
return wallet.getHistory();
},
- ["get-offer"]: function (detail, sender) {
+ ["get-offer"]: (detail, sender) => {
return wallet.getOffer(detail.offerId);
},
- ["get-exchanges"]: function (detail, sender) {
+ ["get-exchanges"]: (detail, sender) => {
return wallet.getExchanges();
},
- ["get-currencies"]: function (detail, sender) {
+ ["get-currencies"]: (detail, sender) => {
return wallet.getCurrencies();
},
- ["update-currency"]: function (detail, sender) {
+ ["update-currency"]: (detail, sender) => {
return wallet.updateCurrency(detail.currencyRecord);
},
- ["get-reserves"]: function (detail, sender) {
+ ["get-reserves"]: (detail, sender) => {
if (typeof detail.exchangeBaseUrl !== "string") {
return Promise.reject(Error("exchangeBaseUrl missing"));
}
return wallet.getReserves(detail.exchangeBaseUrl);
},
- ["get-payback-reserves"]: function (detail, sender) {
+ ["get-payback-reserves"]: (detail, sender) => {
return wallet.getPaybackReserves();
},
- ["withdraw-payback-reserve"]: function (detail, sender) {
+ ["withdraw-payback-reserve"]: (detail, sender) => {
if (typeof detail.reservePub !== "string") {
return Promise.reject(Error("reservePub missing"));
}
return wallet.withdrawPaybackReserve(detail.reservePub);
},
- ["get-coins"]: function (detail, sender) {
+ ["get-coins"]: (detail, sender) => {
if (typeof detail.exchangeBaseUrl !== "string") {
return Promise.reject(Error("exchangBaseUrl missing"));
}
return wallet.getCoins(detail.exchangeBaseUrl);
},
- ["get-precoins"]: function (detail, sender) {
+ ["get-precoins"]: (detail, sender) => {
if (typeof detail.exchangeBaseUrl !== "string") {
return Promise.reject(Error("exchangBaseUrl missing"));
}
return wallet.getPreCoins(detail.exchangeBaseUrl);
},
- ["get-denoms"]: function (detail, sender) {
+ ["get-denoms"]: (detail, sender) => {
if (typeof detail.exchangeBaseUrl !== "string") {
return Promise.reject(Error("exchangBaseUrl missing"));
}
return wallet.getDenoms(detail.exchangeBaseUrl);
},
- ["refresh-coin"]: function (detail, sender) {
+ ["refresh-coin"]: (detail, sender) => {
if (typeof detail.coinPub !== "string") {
return Promise.reject(Error("coinPub missing"));
}
return wallet.refresh(detail.coinPub);
},
- ["payback-coin"]: function (detail, sender) {
+ ["payback-coin"]: (detail, sender) => {
if (typeof detail.coinPub !== "string") {
return Promise.reject(Error("coinPub missing"));
}
return wallet.payback(detail.coinPub);
},
- ["payment-failed"]: function (detail, sender) {
+ ["payment-failed"]: (detail, sender) => {
// For now we just update exchanges (maybe the exchange did something
// wrong and the keys were messed up).
// FIXME: in the future we should look at what actually went wrong.
@@ -280,9 +284,9 @@ function makeHandlers(db: IDBDatabase,
wallet.updateExchanges();
return Promise.resolve();
},
- ["payment-succeeded"]: function (detail, sender) {
- let contractHash = detail.contractHash;
- let merchantSig = detail.merchantSig;
+ ["payment-succeeded"]: (detail, sender) => {
+ const contractHash = detail.contractHash;
+ const merchantSig = detail.merchantSig;
if (!contractHash) {
return Promise.reject(Error("contractHash missing"));
}
@@ -307,7 +311,7 @@ async function dispatch(handlers: any, req: any, sender: any, sendResponse: any)
try {
const p = handlers[req.type](req.detail, sender);
- let r = await p;
+ const r = await p;
try {
sendResponse(r);
} catch (e) {
@@ -317,7 +321,7 @@ async function dispatch(handlers: any, req: any, sender: any, sendResponse: any)
console.log(`exception during wallet handler for '${req.type}'`);
console.log("request", req);
console.error(e);
- let stack = undefined;
+ let stack;
try {
stack = e.stack.toString();
} catch (e) {
@@ -325,9 +329,9 @@ async function dispatch(handlers: any, req: any, sender: any, sendResponse: any)
}
try {
sendResponse({
- stack,
error: "exception",
hint: e.message,
+ stack,
});
} catch (e) {
console.log(e);
@@ -344,7 +348,7 @@ class ChromeNotifier implements Notifier {
console.log("got connect!");
this.ports.push(port);
port.onDisconnect.addListener(() => {
- let i = this.ports.indexOf(port);
+ const i = this.ports.indexOf(port);
if (i >= 0) {
this.ports.splice(i, 1);
} else {
@@ -355,7 +359,7 @@ class ChromeNotifier implements Notifier {
}
notify() {
- for (let p of this.ports) {
+ for (const p of this.ports) {
p.postMessage({ notify: true });
}
}
@@ -365,7 +369,7 @@ class ChromeNotifier implements Notifier {
/**
* Mapping from tab ID to payment information (if any).
*/
-let paymentRequestCookies: { [n: number]: any } = {};
+const paymentRequestCookies: { [n: number]: any } = {};
/**
@@ -376,19 +380,19 @@ let paymentRequestCookies: { [n: number]: any } = {};
*/
function handleHttpPayment(headerList: chrome.webRequest.HttpHeader[], url: string, tabId: number): any {
const headers: { [s: string]: string } = {};
- for (let kv of headerList) {
+ for (const kv of headerList) {
if (kv.value) {
headers[kv.name.toLowerCase()] = kv.value;
}
}
- let fields = {
- contract_url: headers["x-taler-contract-url"],
+ const fields = {
contract_query: headers["x-taler-contract-query"],
+ contract_url: headers["x-taler-contract-url"],
offer_url: headers["x-taler-offer-url"],
- }
+ };
- let talerHeaderFound = Object.keys(fields).filter((x: any) => (fields as any)[x]).length !== 0;
+ const talerHeaderFound = Object.keys(fields).filter((x: any) => (fields as any)[x]).length !== 0;
if (!talerHeaderFound) {
// looks like it's not a taler request, it might be
@@ -397,27 +401,26 @@ function handleHttpPayment(headerList: chrome.webRequest.HttpHeader[], url: stri
return;
}
- let payDetail = {
+ const payDetail = {
contract_url: fields.contract_url,
offer_url: fields.offer_url,
};
- console.log("got pay detail", payDetail)
+ console.log("got pay detail", payDetail);
// This cookie will be read by the injected content script
// in the tab that displays the page.
paymentRequestCookies[tabId] = {
- type: "pay",
payDetail,
+ type: "pay",
};
}
-
function handleBankRequest(wallet: Wallet, headerList: chrome.webRequest.HttpHeader[],
- url: string, tabId: number): any {
+ url: string, tabId: number): any {
const headers: { [s: string]: string } = {};
- for (let kv of headerList) {
+ for (const kv of headerList) {
if (kv.value) {
headers[kv.name.toLowerCase()] = kv.value;
}
@@ -432,7 +435,7 @@ function handleBankRequest(wallet: Wallet, headerList: chrome.webRequest.HttpHea
const amount = headers["x-taler-amount"];
if (amount) {
- let callbackUrl = headers["x-taler-callback-url"];
+ const callbackUrl = headers["x-taler-callback-url"];
if (!callbackUrl) {
console.log("202 not understood (X-Taler-Callback-Url missing)");
return;
@@ -441,30 +444,29 @@ function handleBankRequest(wallet: Wallet, headerList: chrome.webRequest.HttpHea
try {
amountParsed = JSON.parse(amount);
} catch (e) {
- let uri = new URI(chrome.extension.getURL("/src/pages/error.html"));
- let p = {
+ const uri = new URI(chrome.extension.getURL("/src/pages/error.html"));
+ const p = {
message: `Can't parse amount ("${amount}"): ${e.message}`,
};
- let redirectUrl = uri.query(p).href();
+ const redirectUrl = uri.query(p).href();
// FIXME: use direct redirect when https://bugzilla.mozilla.org/show_bug.cgi?id=707624 is fixed
chrome.tabs.update(tabId, {url: redirectUrl});
return;
}
- let wtTypes = headers["x-taler-wt-types"];
+ const wtTypes = headers["x-taler-wt-types"];
if (!wtTypes) {
console.log("202 not understood (X-Taler-Wt-Types missing)");
return;
}
- let params = {
- amount: amount,
- callback_url: new URI(callbackUrl)
- .absoluteTo(url),
+ const params = {
+ amount,
bank_url: url,
- wt_types: wtTypes,
+ callback_url: new URI(callbackUrl) .absoluteTo(url),
suggested_exchange_url: headers["x-taler-suggested-exchange"],
+ wt_types: wtTypes,
};
- let uri = new URI(chrome.extension.getURL("/src/pages/confirm-create-reserve.html"));
- let redirectUrl = uri.query(params).href();
+ const uri = new URI(chrome.extension.getURL("/src/pages/confirm-create-reserve.html"));
+ const redirectUrl = uri.query(params).href();
console.log("redirecting to", redirectUrl);
// FIXME: use direct redirect when https://bugzilla.mozilla.org/show_bug.cgi?id=707624 is fixed
chrome.tabs.update(tabId, {url: redirectUrl});
@@ -484,21 +486,21 @@ function clearRateLimitCache() {
export async function wxMain() {
window.onerror = (m, source, lineno, colno, error) => {
logging.record("error", m + error, undefined, source || "(unknown)", lineno || 0, colno || 0);
- }
+ };
chrome.browserAction.setBadgeText({ text: "" });
const badge = new ChromeBadge();
- chrome.tabs.query({}, function (tabs) {
- for (let tab of tabs) {
+ chrome.tabs.query({}, (tabs) => {
+ for (const tab of tabs) {
if (!tab.url || !tab.id) {
return;
}
- let uri = new URI(tab.url);
+ const uri = new URI(tab.url);
if (uri.protocol() === "http" || uri.protocol() === "https") {
console.log("injecting into existing tab", tab.id);
chrome.tabs.executeScript(tab.id, { file: "/dist/contentScript-bundle.js" });
- let code = `
+ const code = `
if (("taler" in window) || document.documentElement.getAttribute("data-taler-nojs")) {
document.dispatchEvent(new Event("taler-probe-result"));
}
@@ -511,13 +513,13 @@ export async function wxMain() {
const tabTimers: {[n: number]: number[]} = {};
chrome.tabs.onRemoved.addListener((tabId, changeInfo) => {
- let tt = tabTimers[tabId] || [];
- for (let t of tt) {
+ const tt = tabTimers[tabId] || [];
+ for (const t of tt) {
chrome.extension.getBackgroundPage().clearTimeout(t);
}
});
chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
- if (changeInfo.status !== 'complete') {
+ if (changeInfo.status !== "complete") {
return;
}
const timers: number[] = [];
@@ -525,7 +527,7 @@ export async function wxMain() {
const addRun = (dt: number) => {
const id = chrome.extension.getBackgroundPage().setTimeout(run, dt);
timers.push(id);
- }
+ };
const run = () => {
timers.shift();
@@ -536,11 +538,11 @@ export async function wxMain() {
if (!tab.url || !tab.id) {
return;
}
- let uri = new URI(tab.url);
+ const uri = new URI(tab.url);
if (!(uri.protocol() === "http" || uri.protocol() === "https")) {
return;
}
- let code = `
+ const code = `
if (("taler" in window) || document.documentElement.getAttribute("data-taler-nojs")) {
document.dispatchEvent(new Event("taler-probe-result"));
}
@@ -600,7 +602,6 @@ export async function wxMain() {
}
-
/**
* Return a promise that resolves
* to the taler wallet db.
@@ -620,13 +621,13 @@ function openTalerDb(): Promise<IDBDatabase> {
switch (e.oldVersion) {
case 0: // DB does not exist yet
- for (let n in Stores) {
+ for (const n in Stores) {
if ((Stores as any)[n] instanceof Store) {
- let si: Store<any> = (Stores as any)[n];
+ const si: Store<any> = (Stores as any)[n];
const s = db.createObjectStore(si.name, si.storeParams);
- for (let indexName in (si as any)) {
+ for (const indexName in (si as any)) {
if ((si as any)[indexName] instanceof Index) {
- let ii: Index<any, any> = (si as any)[indexName];
+ const ii: Index<any, any> = (si as any)[indexName];
s.createIndex(ii.indexName, ii.keyPath);
}
}
@@ -649,31 +650,32 @@ function openTalerDb(): Promise<IDBDatabase> {
function exportDb(db: IDBDatabase): Promise<any> {
- let dump = {
+ const dump = {
name: db.name,
- version: db.version,
stores: {} as {[s: string]: any},
+ version: db.version,
};
return new Promise((resolve, reject) => {
- let tx = db.transaction(Array.from(db.objectStoreNames));
+ const tx = db.transaction(Array.from(db.objectStoreNames));
tx.addEventListener("complete", () => {
resolve(dump);
});
+ // tslint:disable-next-line:prefer-for-of
for (let i = 0; i < db.objectStoreNames.length; i++) {
- let name = db.objectStoreNames[i];
- let storeDump = {} as {[s: string]: any};
+ const name = db.objectStoreNames[i];
+ const storeDump = {} as {[s: string]: any};
dump.stores[name] = storeDump;
- let store = tx.objectStore(name)
- .openCursor()
- .addEventListener("success", (e: Event) => {
- let cursor = (e.target as any).result;
- if (cursor) {
- storeDump[cursor.key] = cursor.value;
- cursor.continue();
- }
- });
+ tx.objectStore(name)
+ .openCursor()
+ .addEventListener("success", (e: Event) => {
+ const cursor = (e.target as any).result;
+ if (cursor) {
+ storeDump[cursor.key] = cursor.value;
+ cursor.continue();
+ }
+ });
}
});
}
@@ -682,17 +684,20 @@ function exportDb(db: IDBDatabase): Promise<any> {
function importDb(db: IDBDatabase, dump: any): Promise<void> {
console.log("importing db", dump);
return new Promise<void>((resolve, reject) => {
- let tx = db.transaction(Array.from(db.objectStoreNames), "readwrite");
- for (let storeName in dump.stores) {
- let objects = [];
- for (let key in dump.stores[storeName]) {
- objects.push(dump.stores[storeName][key]);
- }
- console.log(`importing ${objects.length} records into ${storeName}`);
- let store = tx.objectStore(storeName);
- let clearReq = store.clear();
- for (let obj of objects) {
- store.put(obj);
+ const tx = db.transaction(Array.from(db.objectStoreNames), "readwrite");
+ if (dump.stores) {
+ for (const storeName in dump.stores) {
+ const objects = [];
+ const dumpStore = dump.stores[storeName];
+ for (const key in dumpStore) {
+ objects.push(dumpStore[key]);
+ }
+ console.log(`importing ${objects.length} records into ${storeName}`);
+ const store = tx.objectStore(storeName);
+ const clearReq = store.clear();
+ for (const obj of objects) {
+ store.put(obj);
+ }
}
}
tx.addEventListener("complete", () => {