From 9a197d619c02f7787311b191da3da693380304b6 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 1 Mar 2016 19:39:17 +0100 Subject: mint->exchange --- lib/wallet/wxMessaging.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/wallet/wxMessaging.ts') diff --git a/lib/wallet/wxMessaging.ts b/lib/wallet/wxMessaging.ts index 740873d88..a6b3f9d1b 100644 --- a/lib/wallet/wxMessaging.ts +++ b/lib/wallet/wxMessaging.ts @@ -60,7 +60,7 @@ function makeHandlers(db: IDBDatabase, }, ["create-reserve"]: function(detail) { const d = { - mint: detail.mint, + exchange: detail.exchange, amount: detail.amount, }; const req = CreateReserveRequest.checked(d); @@ -96,11 +96,11 @@ function makeHandlers(db: IDBDatabase, ["execute-payment"]: function(detail) { return wallet.executePayment(detail.H_contract); }, - ["mint-info"]: function(detail) { + ["exchange-info"]: function(detail) { if (!detail.baseUrl) { return Promise.resolve({error: "bad url"}); } - return wallet.updateMintFromUrl(detail.baseUrl); + return wallet.updateExchangeFromUrl(detail.baseUrl); }, ["reserve-creation-info"]: function(detail) { if (!detail.baseUrl || typeof detail.baseUrl !== "string") { -- cgit v1.2.3 From 7c03db9ba0fcbf10da8fc37ff55b6d987aab8541 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 2 Mar 2016 00:47:00 +0100 Subject: db versioning --- content_scripts/notify.js | 6 ++++-- lib/wallet/db.ts | 14 ++++++++++++-- lib/wallet/wallet.ts | 7 +++++-- lib/wallet/wxMessaging.ts | 8 +++++--- popup/popup.tsx | 32 +++++++++++++++++++++++++++----- 5 files changed, 53 insertions(+), 14 deletions(-) (limited to 'lib/wallet/wxMessaging.ts') diff --git a/content_scripts/notify.js b/content_scripts/notify.js index ee0d96d72..1a8f56b99 100644 --- a/content_scripts/notify.js +++ b/content_scripts/notify.js @@ -13,12 +13,14 @@ You should have received a copy of the GNU General Public License along with TALER; see the file COPYING. If not, If not, see */ -/// -"use strict"; /** * Script that is injected into (all!) pages to allow them * to interact with the GNU Taler wallet via DOM Events. + * + * @author Florian Dold */ +/// +"use strict"; // Make sure we don't pollute the namespace too much. var TalerNotify; (function (TalerNotify) { diff --git a/lib/wallet/db.ts b/lib/wallet/db.ts index 2503468d5..9374aa447 100644 --- a/lib/wallet/db.ts +++ b/lib/wallet/db.ts @@ -25,7 +25,7 @@ */ const DB_NAME = "taler"; -const DB_VERSION = 1; +const DB_VERSION = 5; /** * Return a promise that resolves @@ -45,7 +45,8 @@ export function openTalerDb(): Promise { console.log("DB: upgrade needed: oldVersion = " + e.oldVersion); switch (e.oldVersion) { case 0: // DB does not exist yet - const exchanges = db.createObjectStore("exchanges", {keyPath: "baseUrl"}); + const exchanges = db.createObjectStore("exchanges", + {keyPath: "baseUrl"}); exchanges.createIndex("pubKey", "masterPublicKey"); db.createObjectStore("reserves", {keyPath: "reserve_pub"}); db.createObjectStore("denoms", {keyPath: "denomPub"}); @@ -68,6 +69,15 @@ export function openTalerDb(): Promise { }); history.createIndex("timestamp", "timestamp"); break; + default: + if (e.oldVersion != DB_VERSION) { + window.alert("Incompatible wallet dababase version, please reset" + + " db."); + chrome.browserAction.setBadgeText({text: "R!"}); + chrome.browserAction.setBadgeBackgroundColor({color: "#F00"}); + throw Error("incompatible DB"); + } + break; } }; }); diff --git a/lib/wallet/wallet.ts b/lib/wallet/wallet.ts index 94ac8ee8a..3764edfbc 100644 --- a/lib/wallet/wallet.ts +++ b/lib/wallet/wallet.ts @@ -912,7 +912,10 @@ export class Wallet { return Query(this.db) .iter("coins") - .reduce(collectBalances, {}); + .reduce(collectBalances, {}) + .then(byCurrency => { + return {balances: byCurrency}; + }); } @@ -922,7 +925,7 @@ export class Wallet { getHistory(): Promise { function collect(x, acc) { acc.push(x); - return acc; + return {history: acc}; } return Query(this.db) diff --git a/lib/wallet/wxMessaging.ts b/lib/wallet/wxMessaging.ts index a6b3f9d1b..d49a80efb 100644 --- a/lib/wallet/wxMessaging.ts +++ b/lib/wallet/wxMessaging.ts @@ -47,9 +47,11 @@ function makeHandlers(db: IDBDatabase, return exportDb(db); }, ["reset"]: function(detail) { - let tx = db.transaction(db.objectStoreNames, 'readwrite'); - for (let i = 0; i < db.objectStoreNames.length; i++) { - tx.objectStore(db.objectStoreNames[i]).clear(); + if (db) { + let tx = db.transaction(db.objectStoreNames, 'readwrite'); + for (let i = 0; i < db.objectStoreNames.length; i++) { + tx.objectStore(db.objectStoreNames[i]).clear(); + } } deleteDb(); diff --git a/popup/popup.tsx b/popup/popup.tsx index 2cd753e4f..be33f870a 100644 --- a/popup/popup.tsx +++ b/popup/popup.tsx @@ -95,6 +95,7 @@ namespace WalletBalance { class Controller { myWallet; + gotError = false; constructor() { this.updateBalance(); @@ -104,9 +105,16 @@ namespace WalletBalance { updateBalance() { m.startComputation(); - chrome.runtime.sendMessage({type: "balances"}, (wallet) => { - console.log("got wallet", wallet); - this.myWallet = wallet; + chrome.runtime.sendMessage({type: "balances"}, (resp) => { + if (resp.error) { + this.gotError = true; + console.error("could not retrieve balances", resp); + m.endComputation(); + return; + } + this.gotError = false; + console.log("got wallet", resp); + this.myWallet = resp.balances; m.endComputation(); }); } @@ -114,6 +122,9 @@ namespace WalletBalance { export function view(ctrl: Controller) { let wallet = ctrl.myWallet; + if (ctrl.gotError) { + return i18n`Error: could not retrieve balance information.`; + } if (!wallet) { throw Error("Could not retrieve wallet"); } @@ -200,6 +211,7 @@ namespace WalletHistory { class Controller { myHistory; + gotError = false; constructor() { this.update(); @@ -209,8 +221,15 @@ namespace WalletHistory { update() { m.startComputation(); chrome.runtime.sendMessage({type: "get-history"}, (resp) => { - console.log("got history", history); - this.myHistory = resp; + if (resp.error) { + this.gotError = true; + console.error("could not retrieve history", resp); + m.endComputation(); + return; + } + this.gotError = false; + console.log("got history", resp.history); + this.myHistory = resp.history; m.endComputation(); }); } @@ -218,6 +237,9 @@ namespace WalletHistory { export function view(ctrl: Controller) { let history = ctrl.myHistory; + if (ctrl.gotError) { + return i18n`Error: could not retrieve event history`; + } if (!history) { throw Error("Could not retrieve history"); } -- cgit v1.2.3 From 8714240c909d9c2f2deeb6ae99f219295f67c708 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 2 Mar 2016 02:16:18 +0100 Subject: show accepted exchanges --- lib/decl/mithril.d.ts | 2 +- lib/wallet/types.ts | 63 +++++++++++++++++++++++++++++++++++++++++++++ lib/wallet/wallet.ts | 64 ++-------------------------------------------- lib/wallet/wxMessaging.ts | 2 +- pages/confirm-contract.tsx | 38 ++++++++++++++++++++++++--- 5 files changed, 102 insertions(+), 67 deletions(-) (limited to 'lib/wallet/wxMessaging.ts') diff --git a/lib/decl/mithril.d.ts b/lib/decl/mithril.d.ts index c87102260..c45633490 100644 --- a/lib/decl/mithril.d.ts +++ b/lib/decl/mithril.d.ts @@ -608,7 +608,7 @@ declare module _mithril { * * @see m.component */ - controller: MithrilControllerFunction | + controller?: MithrilControllerFunction | MithrilControllerConstructor; /** diff --git a/lib/wallet/types.ts b/lib/wallet/types.ts index 748df6f4c..feab1bcb1 100644 --- a/lib/wallet/types.ts +++ b/lib/wallet/types.ts @@ -150,6 +150,69 @@ export interface Coin { } +@Checkable.Class +export class ExchangeHandle { + @Checkable.String + master_pub: string; + + @Checkable.String + url: string; + + static checked: (obj: any) => ExchangeHandle; +} + + +@Checkable.Class +export class Contract { + @Checkable.String + H_wire: string; + + @Checkable.Value(AmountJson) + amount: AmountJson; + + @Checkable.List(Checkable.AnyObject) + auditors: any[]; + + @Checkable.String + expiry: string; + + @Checkable.Any + locations: any; + + @Checkable.Value(AmountJson) + max_fee: AmountJson; + + @Checkable.Any + merchant: any; + + @Checkable.String + merchant_pub: string; + + @Checkable.List(Checkable.Value(ExchangeHandle)) + exchanges: ExchangeHandle[]; + + @Checkable.List(Checkable.AnyObject) + products: any[]; + + @Checkable.String + refund_deadline: string; + + @Checkable.String + timestamp: string; + + @Checkable.Number + transaction_id: number; + + @Checkable.String + fulfillment_url: string; + + @Checkable.Optional(Checkable.String) + repurchase_correlation_id: string; + + static checked: (obj: any) => Contract; +} + + export type PayCoinInfo = Array<{ updatedCoin: Coin, sig: CoinPaySig }>; diff --git a/lib/wallet/wallet.ts b/lib/wallet/wallet.ts index 3764edfbc..0dc232bb0 100644 --- a/lib/wallet/wallet.ts +++ b/lib/wallet/wallet.ts @@ -33,6 +33,8 @@ import {CryptoApi} from "./cryptoApi"; import {Coin} from "./types"; import {PayCoinInfo} from "./types"; import {CheckRepurchaseResult} from "./types"; +import {Contract} from "./types"; +import {ExchangeHandle} from "./types"; "use strict"; @@ -182,68 +184,6 @@ export class ConfirmReserveRequest { } -@Checkable.Class -export class ExchangeHandle { - @Checkable.String - master_pub: string; - - @Checkable.String - url: string; - - static checked: (obj: any) => ExchangeHandle; -} - - -@Checkable.Class -export class Contract { - @Checkable.String - H_wire: string; - - @Checkable.Value(AmountJson) - amount: AmountJson; - - @Checkable.List(Checkable.AnyObject) - auditors: any[]; - - @Checkable.String - expiry: string; - - @Checkable.Any - locations: any; - - @Checkable.Value(AmountJson) - max_fee: AmountJson; - - @Checkable.Any - merchant: any; - - @Checkable.String - merchant_pub: string; - - @Checkable.List(Checkable.Value(ExchangeHandle)) - exchanges: ExchangeHandle[]; - - @Checkable.List(Checkable.AnyObject) - products: any[]; - - @Checkable.String - refund_deadline: string; - - @Checkable.String - timestamp: string; - - @Checkable.Number - transaction_id: number; - - @Checkable.String - fulfillment_url: string; - - @Checkable.Optional(Checkable.String) - repurchase_correlation_id: string; - - static checked: (obj: any) => Contract; -} - @Checkable.Class export class Offer { diff --git a/lib/wallet/wxMessaging.ts b/lib/wallet/wxMessaging.ts index d49a80efb..4f496861d 100644 --- a/lib/wallet/wxMessaging.ts +++ b/lib/wallet/wxMessaging.ts @@ -22,7 +22,7 @@ import {Checkable} from "./checkable"; import {AmountJson} from "./types"; import Port = chrome.runtime.Port; import {Notifier} from "./types"; -import {Contract} from "./wallet"; +import {Contract} from "./types"; "use strict"; diff --git a/pages/confirm-contract.tsx b/pages/confirm-contract.tsx index 9ce1b0a5a..0c7419c6c 100644 --- a/pages/confirm-contract.tsx +++ b/pages/confirm-contract.tsx @@ -21,12 +21,14 @@ * @author Florian Dold */ -/// -"use strict"; +/// +import MithrilComponent = _mithril.MithrilComponent; import {substituteFulfillmentUrl} from "../lib/wallet/helpers"; +import m from "mithril"; +import {Contract} from "../lib/wallet/types"; +"use strict"; -declare var m: any; function prettyAmount(amount) { let v = amount.value + amount.fraction / 1e6; @@ -34,6 +36,35 @@ function prettyAmount(amount) { } +const Details = { + controller() { + return {collapsed: m.prop(true)}; + }, + view(ctrl, contract: Contract) { + if (ctrl.collapsed()) { + return m("div", [ + m("button.linky", { + onclick: () => { + ctrl.collapsed(false); + } + }, "show more details") + ]); + } else { + return m("div", [ + m("button.linky", { + onclick: () => { + ctrl.collapsed(true); + } + }, "show less details"), + m("div", [ + "Accepted exchanges:", + m("ul", contract.exchanges.map(e => m("li", `${e.url}: ${e.master_pub}`))) + ]) + ]); + } + } +}; + export function main() { let url = URI(document.location.href); let query: any = URI.parseQuery(url.query()); @@ -58,6 +89,7 @@ export function main() { `${p.description}: ${prettyAmount(p.price)}`))), m("button.confirm-pay", {onclick: doPayment}, i18n`Confirm Payment`), m("p", error ? error : []), + m(Details, contract) ]; } }; -- cgit v1.2.3 From 13a8f36cad4d5d2ffec788ff6b4d5b61ed4ddff9 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 2 Mar 2016 15:33:23 +0100 Subject: re-inject extension on load --- content_scripts/notify.js | 37 ++++++++++++++++++++++++++----------- content_scripts/notify.ts | 43 ++++++++++++++++++++++++++++++------------- lib/wallet/wxMessaging.ts | 13 +++++++++++++ manifest.json | 3 ++- 4 files changed, 71 insertions(+), 25 deletions(-) (limited to 'lib/wallet/wxMessaging.ts') diff --git a/content_scripts/notify.js b/content_scripts/notify.js index aa7dee730..2df089719 100644 --- a/content_scripts/notify.js +++ b/content_scripts/notify.js @@ -34,14 +34,29 @@ var TalerNotify; url = url.replace("${$}", "$"); return url; } - var $ = function (x) { return document.getElementById(x); }; - document.addEventListener("DOMContentLoaded", function (e) { - if (document.documentElement.getAttribute("data-taler-requested")) { - console.log("taler requested in html element"); - document.documentElement.setAttribute("data-taler-extension-id", chrome.runtime.id); + var handlers = []; + var port = chrome.runtime.connect(); + port.onDisconnect.addListener(function () { + console.log("chrome runtime disconnected"); + for (var _i = 0, handlers_1 = handlers; _i < handlers_1.length; _i++) { + var handler = handlers_1[_i]; + document.removeEventListener(handler.type, handler.listener); } }); - document.addEventListener("taler-probe", function (e) { + var $ = function (x) { return document.getElementById(x); }; + function addHandler(type, listener) { + document.addEventListener(type, listener); + handlers.push({ type: type, listener: listener }); + } + addHandler("taler-query-id", function (e) { + var evt = new CustomEvent("taler-id", { + detail: { + id: chrome.runtime.id + } + }); + document.dispatchEvent(evt); + }); + addHandler("taler-probe", function (e) { var evt = new CustomEvent("taler-wallet-present", { detail: { walletProtocolVersion: PROTOCOL_VERSION @@ -50,7 +65,7 @@ var TalerNotify; document.dispatchEvent(evt); console.log("handshake done"); }); - document.addEventListener("taler-create-reserve", function (e) { + addHandler("taler-create-reserve", function (e) { console.log("taler-create-reserve with " + JSON.stringify(e.detail)); var params = { amount: JSON.stringify(e.detail.amount), @@ -61,7 +76,7 @@ var TalerNotify; var uri = URI(chrome.extension.getURL("pages/confirm-create-reserve.html")); document.location.href = uri.query(params).href(); }); - document.addEventListener("taler-confirm-reserve", function (e) { + addHandler("taler-confirm-reserve", function (e) { console.log("taler-confirm-reserve with " + JSON.stringify(e.detail)); var msg = { type: "confirm-reserve", @@ -74,7 +89,7 @@ var TalerNotify; }); }); // XXX: remove in a bit, just here for compatibility ... - document.addEventListener("taler-contract", function (e) { + addHandler("taler-contract", function (e) { // XXX: the merchant should just give us the parsed data ... var offer = JSON.parse(e.detail); if (!offer.contract) { @@ -108,7 +123,7 @@ var TalerNotify; } }); }); - document.addEventListener("taler-confirm-contract", function (e) { + addHandler("taler-confirm-contract", function (e) { if (!e.detail.contract_wrapper) { console.error("contract wrapper missing"); return; @@ -151,7 +166,7 @@ var TalerNotify; } }); }); - document.addEventListener('taler-execute-payment', function (e) { + addHandler('taler-execute-payment', function (e) { console.log("got taler-execute-payment in content page"); if (!e.detail.pay_url) { console.log("field 'pay_url' missing in taler-execute-payment event"); diff --git a/content_scripts/notify.ts b/content_scripts/notify.ts index c87c9450e..92c9eee1e 100644 --- a/content_scripts/notify.ts +++ b/content_scripts/notify.ts @@ -43,17 +43,34 @@ namespace TalerNotify { return url; } - let $ = (x) => document.getElementById(x); + let handlers = []; - document.addEventListener("DOMContentLoaded", function(e) { - if (document.documentElement.getAttribute("data-taler-requested")) { - console.log("taler requested in html element"); - document.documentElement.setAttribute("data-taler-extension-id", - chrome.runtime.id); + let port = chrome.runtime.connect(); + port.onDisconnect.addListener(() => { + console.log("chrome runtime disconnected"); + for (let handler of handlers) { + document.removeEventListener(handler.type, handler.listener); } }); - document.addEventListener("taler-probe", function(e) { + let $ = (x) => document.getElementById(x); + + function addHandler(type, listener) { + document.addEventListener(type, listener); + handlers.push({type, listener}); + } + + + addHandler("taler-query-id", function(e) { + let evt = new CustomEvent("taler-id", { + detail: { + id: chrome.runtime.id + } + }); + document.dispatchEvent(evt); + }); + + addHandler("taler-probe", function(e) { let evt = new CustomEvent("taler-wallet-present", { detail: { walletProtocolVersion: PROTOCOL_VERSION @@ -63,7 +80,7 @@ namespace TalerNotify { console.log("handshake done"); }); - document.addEventListener("taler-create-reserve", function(e: CustomEvent) { + addHandler("taler-create-reserve", function(e: CustomEvent) { console.log("taler-create-reserve with " + JSON.stringify(e.detail)); let params = { amount: JSON.stringify(e.detail.amount), @@ -75,7 +92,7 @@ namespace TalerNotify { document.location.href = uri.query(params).href(); }); - document.addEventListener("taler-confirm-reserve", function(e: CustomEvent) { + addHandler("taler-confirm-reserve", function(e: CustomEvent) { console.log("taler-confirm-reserve with " + JSON.stringify(e.detail)); let msg = { type: "confirm-reserve", @@ -90,7 +107,7 @@ namespace TalerNotify { // XXX: remove in a bit, just here for compatibility ... - document.addEventListener("taler-contract", function(e: CustomEvent) { + addHandler("taler-contract", function(e: CustomEvent) { // XXX: the merchant should just give us the parsed data ... let offer = JSON.parse(e.detail); @@ -130,7 +147,7 @@ namespace TalerNotify { }); - document.addEventListener("taler-confirm-contract", function(e: CustomEvent) { + addHandler("taler-confirm-contract", function(e: CustomEvent) { if (!e.detail.contract_wrapper) { console.error("contract wrapper missing"); return; @@ -179,7 +196,7 @@ namespace TalerNotify { }); - document.addEventListener('taler-execute-payment', function(e: CustomEvent) { + addHandler('taler-execute-payment', function(e: CustomEvent) { console.log("got taler-execute-payment in content page"); if (!e.detail.pay_url) { console.log("field 'pay_url' missing in taler-execute-payment event"); @@ -232,4 +249,4 @@ namespace TalerNotify { }; }); }); -} +} \ No newline at end of file diff --git a/lib/wallet/wxMessaging.ts b/lib/wallet/wxMessaging.ts index 4f496861d..daa9ec197 100644 --- a/lib/wallet/wxMessaging.ts +++ b/lib/wallet/wxMessaging.ts @@ -195,6 +195,19 @@ class ChromeNotifier implements Notifier { export function wxMain() { chrome.browserAction.setBadgeText({text: ""}); + chrome.tabs.query({}, function(tabs) { + for (let tab of tabs) { + if (!tab.url) { + 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: "content_scripts/notify.js"}); + } + } + }); + Promise.resolve() .then(() => { return openTalerDb(); diff --git a/manifest.json b/manifest.json index 54a5585ef..b83a68533 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "description": "Privacy preserving and transparent payments", "manifest_version": 2, "name": "GNU Taler Wallet (git)", - "version": "0.5.14", + "version": "0.5.15", "applications": { "gecko": { @@ -12,6 +12,7 @@ "permissions": [ "storage", + "tabs", "http://*/*", "https://*/*" ], -- cgit v1.2.3