aboutsummaryrefslogtreecommitdiff
path: root/lib/wallet/wxMessaging.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/wallet/wxMessaging.ts')
-rw-r--r--lib/wallet/wxMessaging.ts439
1 files changed, 0 insertions, 439 deletions
diff --git a/lib/wallet/wxMessaging.ts b/lib/wallet/wxMessaging.ts
deleted file mode 100644
index 07f16f24f..000000000
--- a/lib/wallet/wxMessaging.ts
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- This file is part of TALER
- (C) 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-
-import {
- Wallet,
- Offer,
- Badge,
- ConfirmReserveRequest,
- CreateReserveRequest
-} from "./wallet";
-import { deleteDb, exportDb, openTalerDb } from "./db";
-import { BrowserHttpLib } from "./http";
-import { Checkable } from "./checkable";
-import { AmountJson } from "./types";
-import Port = chrome.runtime.Port;
-import { Notifier } from "./types";
-import { Contract } from "./types";
-import MessageSender = chrome.runtime.MessageSender;
-import { ChromeBadge } from "./chromeBadge";
-
-"use strict";
-
-/**
- * Messaging for the WebExtensions wallet. Should contain
- * parts that are specific for WebExtensions, but as little business
- * logic as possible.
- *
- * @author Florian Dold
- */
-
-
-type Handler = (detail: any, sender: MessageSender) => Promise<any>;
-
-function makeHandlers(db: IDBDatabase,
- wallet: Wallet): { [msg: string]: Handler } {
- return {
- ["balances"]: function (detail, sender) {
- return wallet.getBalances();
- },
- ["dump-db"]: function (detail, sender) {
- return exportDb(db);
- },
- ["get-tab-cookie"]: function (detail, sender) {
- if (!sender || !sender.tab || !sender.tab.id) {
- return Promise.resolve();
- }
- let id: number = sender.tab.id;
- let info: any = <any>paymentRequestCookies[id];
- delete paymentRequestCookies[id];
- return Promise.resolve(info);
- },
- ["ping"]: function (detail, sender) {
- return Promise.resolve();
- },
- ["reset"]: function (detail, sender) {
- if (db) {
- let tx = db.transaction(Array.from(db.objectStoreNames), 'readwrite');
- for (let i = 0; i < db.objectStoreNames.length; i++) {
- tx.objectStore(db.objectStoreNames[i]).clear();
- }
- }
- deleteDb();
-
- chrome.browserAction.setBadgeText({ text: "" });
- console.log("reset done");
- // Response is synchronous
- return Promise.resolve({});
- },
- ["create-reserve"]: function (detail, sender) {
- const d = {
- exchange: detail.exchange,
- amount: detail.amount,
- };
- const req = CreateReserveRequest.checked(d);
- return wallet.createReserve(req);
- },
- ["confirm-reserve"]: function (detail, sender) {
- // TODO: make it a checkable
- const d = {
- reservePub: detail.reservePub
- };
- const req = ConfirmReserveRequest.checked(d);
- return wallet.confirmReserve(req);
- },
- ["confirm-pay"]: function (detail, sender) {
- let offer: Offer;
- try {
- offer = Offer.checked(detail.offer);
- } catch (e) {
- if (e instanceof Checkable.SchemaError) {
- console.error("schema error:", e.message);
- return Promise.resolve({
- error: "invalid contract",
- hint: e.message,
- detail: detail
- });
- } else {
- throw e;
- }
- }
-
- return wallet.confirmPay(offer);
- },
- ["check-pay"]: function (detail, sender) {
- let offer: Offer;
- try {
- offer = Offer.checked(detail.offer);
- } catch (e) {
- if (e instanceof Checkable.SchemaError) {
- console.error("schema error:", e.message);
- return Promise.resolve({
- error: "invalid contract",
- hint: e.message,
- detail: detail
- });
- } else {
- throw e;
- }
- }
- return wallet.checkPay(offer);
- },
- ["execute-payment"]: function (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 execute payment exceeded");
- let msg = {
- error: "rate limit exceeded for execute-payment",
- rateLimitExceeded: true,
- hint: "Check for redirect loops",
- };
- return Promise.resolve(msg);
- }
- }
- return wallet.executePayment(detail.H_contract);
- },
- ["exchange-info"]: function (detail) {
- if (!detail.baseUrl) {
- return Promise.resolve({ error: "bad url" });
- }
- return wallet.updateExchangeFromUrl(detail.baseUrl);
- },
- ["hash-contract"]: function (detail) {
- if (!detail.contract) {
- return Promise.resolve({ error: "contract missing" });
- }
- return wallet.hashContract(detail.contract).then((hash) => {
- return { hash };
- });
- },
- ["put-history-entry"]: function (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;
- if (!offer) {
- return Promise.resolve({ error: "offer missing" });
- }
- console.log("handling safe-offer");
- return wallet.saveOffer(offer);
- },
- ["reserve-creation-info"]: function (detail, sender) {
- if (!detail.baseUrl || typeof detail.baseUrl !== "string") {
- return Promise.resolve({ error: "bad url" });
- }
- let amount = AmountJson.checked(detail.amount);
- return wallet.getReserveCreationInfo(detail.baseUrl, amount);
- },
- ["check-repurchase"]: function (detail, sender) {
- let contract = Contract.checked(detail.contract);
- return wallet.checkRepurchase(contract);
- },
- ["get-history"]: function (detail, sender) {
- // TODO: limit history length
- return wallet.getHistory();
- },
- ["get-offer"]: function (detail, sender) {
- return wallet.getOffer(detail.offerId);
- },
- ["get-exchanges"]: function (detail, sender) {
- return wallet.getExchanges();
- },
- ["get-reserves"]: function (detail, sender) {
- if (typeof detail.exchangeBaseUrl !== "string") {
- return Promise.reject(Error("exchangeBaseUrl missing"));
- }
- return wallet.getReserves(detail.exchangeBaseUrl);
- },
- ["get-coins"]: function (detail, sender) {
- if (typeof detail.exchangeBaseUrl !== "string") {
- return Promise.reject(Error("exchangBaseUrl missing"));
- }
- return wallet.getCoins(detail.exchangeBaseUrl);
- },
- ["get-precoins"]: function (detail, sender) {
- if (typeof detail.exchangeBaseUrl !== "string") {
- return Promise.reject(Error("exchangBaseUrl missing"));
- }
- return wallet.getPreCoins(detail.exchangeBaseUrl);
- },
- ["refresh-coin"]: function (detail, sender) {
- if (typeof detail.coinPub !== "string") {
- return Promise.reject(Error("coinPub missing"));
- }
- return wallet.refresh(detail.coinPub);
- },
- ["payment-failed"]: function (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.
- console.error("payment reported as failed");
- wallet.updateExchanges();
- return Promise.resolve();
- },
- ["payment-succeeded"]: function (detail, sender) {
- let contractHash = detail.contractHash;
- if (!contractHash) {
- return Promise.reject(Error("contractHash missing"));
- }
- return wallet.paymentSucceeded(contractHash);
- },
- };
-}
-
-
-function dispatch(handlers: any, req: any, sender: any, sendResponse: any) {
- if (req.type in handlers) {
- Promise
- .resolve()
- .then(() => {
- const p = handlers[req.type](req.detail, sender);
-
- return p.then((r: any) => {
- try {
- sendResponse(r);
- } catch (e) {
- // might fail if tab disconnected
- }
- })
- })
- .catch((e) => {
- console.log(`exception during wallet handler for '${req.type}'`);
- console.log("request", req);
- console.error(e);
- try {
- sendResponse({
- error: "exception",
- hint: e.message,
- stack: e.stack.toString()
- });
-
- } catch (e) {
- // might fail if tab disconnected
- }
- });
- // The sendResponse call is async
- return true;
- } else {
- console.error(`Request type ${JSON.stringify(req)} unknown, req ${req.type}`);
- try {
- sendResponse({ error: "request unknown" });
- } catch (e) {
- // might fail if tab disconnected
- }
-
- // The sendResponse call is sync
- return false;
- }
-}
-
-class ChromeNotifier implements Notifier {
- ports: Port[] = [];
-
- constructor() {
- chrome.runtime.onConnect.addListener((port) => {
- console.log("got connect!");
- this.ports.push(port);
- port.onDisconnect.addListener(() => {
- let i = this.ports.indexOf(port);
- if (i >= 0) {
- this.ports.splice(i, 1);
- } else {
- console.error("port already removed");
- }
- });
- });
- }
-
- notify() {
- for (let p of this.ports) {
- p.postMessage({ notify: true });
- }
- }
-}
-
-
-/**
- * Mapping from tab ID to payment information (if any).
- */
-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) {
- if (kv.value) {
- headers[kv.name.toLowerCase()] = kv.value;
- }
- }
-
- const contractUrl = headers["x-taler-contract-url"];
- if (contractUrl !== undefined) {
- paymentRequestCookies[tabId] = { type: "fetch", contractUrl };
- return;
- }
-
- const contractHash = headers["x-taler-contract-hash"];
-
- if (contractHash !== undefined) {
- const payUrl = headers["x-taler-pay-url"];
- if (payUrl === undefined) {
- console.log("malformed 402, X-Taler-Pay-Url missing");
- return;
- }
-
- // Offer URL is optional
- const offerUrl = headers["x-taler-offer-url"];
- paymentRequestCookies[tabId] = {
- type: "execute",
- offerUrl,
- payUrl,
- contractHash
- };
- return;
- }
-
- // looks like it's not a taler request, it might be
- // for a different payment system (or the shop is buggy)
- console.log("ignoring non-taler 402 response");
-}
-
-// Useful for debugging ...
-export let wallet: Wallet | undefined = undefined;
-export let badge: ChromeBadge | undefined = undefined;
-
-// Rate limit cache for executePayment operations, to break redirect loops
-let rateLimitCache: { [n: number]: number } = {};
-
-function clearRateLimitCache() {
- rateLimitCache = {};
-}
-
-export function wxMain() {
- chrome.browserAction.setBadgeText({ text: "" });
- badge = new ChromeBadge();
-
- chrome.tabs.query({}, function (tabs) {
- for (let tab of tabs) {
- if (!tab.url || !tab.id) {
- return;
- }
- let uri = URI(tab.url);
- if (uri.protocol() == "http" || uri.protocol() == "https") {
- console.log("injecting into existing tab", tab.id);
- chrome.tabs.executeScript(tab.id, { file: "lib/vendor/URI.js" });
- chrome.tabs.executeScript(tab.id, { file: "lib/taler-wallet-lib.js" });
- chrome.tabs.executeScript(tab.id, { file: "content_scripts/notify.js" });
- }
- }
- });
-
- chrome.extension.getBackgroundPage().setInterval(clearRateLimitCache, 5000);
-
- Promise.resolve()
- .then(() => {
- return openTalerDb();
- })
- .catch((e) => {
- console.error("could not open database");
- console.error(e);
- })
- .then((db: IDBDatabase) => {
- let http = new BrowserHttpLib();
- let notifier = new ChromeNotifier();
- console.log("setting wallet");
- wallet = new Wallet(db, http, badge!, notifier);
-
- // Handlers for messages coming directly from the content
- // script on the page
- let handlers = makeHandlers(db, wallet!);
- chrome.runtime.onMessage.addListener((req, sender, sendResponse) => {
- try {
- return dispatch(handlers, req, sender, sendResponse)
- } catch (e) {
- console.log(`exception during wallet handler (dispatch)`);
- console.log("request", req);
- console.error(e);
- sendResponse({
- error: "exception",
- hint: e.message,
- stack: e.stack.toString()
- });
- return false;
- }
- });
-
- // Handlers for catching HTTP requests
- chrome.webRequest.onHeadersReceived.addListener((details) => {
- if (details.statusCode != 402) {
- return;
- }
- console.log(`got 402 from ${details.url}`);
- return handleHttpPayment(details.responseHeaders || [],
- details.url,
- details.tabId);
- }, { urls: ["<all_urls>"] }, ["responseHeaders", "blocking"]);
- })
- .catch((e) => {
- console.error("could not initialize wallet messaging");
- console.error(e);
- });
-}