diff options
| -rw-r--r-- | src/types.ts | 46 | ||||
| -rw-r--r-- | src/wallet.ts | 46 | ||||
| -rw-r--r-- | src/webex/messages.ts | 64 | ||||
| -rw-r--r-- | src/webex/notify.ts | 64 | ||||
| -rw-r--r-- | src/webex/pages/popup.tsx | 6 | ||||
| -rw-r--r-- | src/webex/wxApi.ts | 116 | ||||
| -rw-r--r-- | src/webex/wxBackend.ts | 6 | ||||
| -rw-r--r-- | tsconfig.json | 3 | 
8 files changed, 195 insertions, 156 deletions
| diff --git a/src/types.ts b/src/types.ts index c4b6c466a..4dee93a10 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1358,3 +1358,49 @@ export type CheckPayResult = "paid" | "payment-possible" | "insufficient-balance   * Possible results for confirmPay.   */  export type ConfirmPayResult = "paid" | "insufficient-balance"; + + +/** + * Level of detail at which a history + * entry should be shown. + */ +export enum HistoryLevel { +  Trace = 1, +  Developer = 2, +  Expert = 3, +  User = 4, +} + + +/* + * Activity history record. + */ +export interface HistoryRecord { +  /** +   * Type of the history event. +   */ +  type: string; + +  /** +   * Time when the activity was recorded. +   */ +  timestamp: number; + +  /** +   * Subject of the entry.  Used to group multiple history records together. +   * Only the latest history record with the same subjectId will be shown. +   */ +  subjectId?: string; + +  /** +   * Details used when rendering the history record. +   */ +  detail: any; + +  /** +   * Level of detail of the history entry. +   */ +  level: HistoryLevel; +} + + diff --git a/src/wallet.ts b/src/wallet.ts index 92187d82f..51c99e805 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -60,6 +60,8 @@ import {    ExchangeHandle,    ExchangeRecord,    ExchangeWireFeesRecord, +  HistoryLevel, +  HistoryRecord,    Notifier,    OfferRecord,    PayCoinInfo, @@ -270,38 +272,6 @@ export class ConfirmReserveRequest {  } -/** - * Activity history record. - */ -export interface HistoryRecord { -  /** -   * Type of the history event. -   */ -  type: string; - -  /** -   * Time when the activity was recorded. -   */ -  timestamp: number; - -  /** -   * Subject of the entry.  Used to group multiple history records together. -   * Only the latest history record with the same subjectId will be shown. -   */ -  subjectId?: string; - -  /** -   * Details used when rendering the history record. -   */ -  detail: any; - -  /** -   * Level of detail of the history entry. -   */ -  level: HistoryLevel; -} - -  interface PayReq {    coins: CoinPaySig[];    merchant_pub: string; @@ -324,18 +294,6 @@ interface TransactionRecord {  /** - * Level of detail at which a history - * entry should be shown. - */ -export enum HistoryLevel { -  Trace = 1, -  Developer = 2, -  Expert = 3, -  User = 4, -} - - -/**   * Badge that shows activity for the wallet.   */  export interface Badge { diff --git a/src/webex/messages.ts b/src/webex/messages.ts new file mode 100644 index 000000000..58bd1b2b1 --- /dev/null +++ b/src/webex/messages.ts @@ -0,0 +1,64 @@ +/* + This file is part of TALER + (C) 2017 Inria and 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/> + */ + +/** + * Type definitions for messages between content scripts/pages and backend. + */ + +// Messages are already documented in wxApi. +/* tslint:disable:completed-docs */ + +import * as types from "../types"; + +export interface MessageMap { +  "balances": { }; +  "dump-db": { }; +  "import-db": { dump: object }; +  "get-tab-cookie": { }; +  "ping": { }; +  "reset": { }; +  "create-reserve": { amount: types.AmountJson; exchange: string };  +  "confirm-reserve": { reservePub: string }; +  "generate-nonce": { }; +  "confirm-pay": { offer: types.OfferRecord; }; +  "check-pay": { offer: types.OfferRecord; }; +  "query-payment": { }; +  "exchange-info": { baseUrl: string }; +  "currency-info": { name: string }; +  "hash-contract": { contract: object }; +  "put-history-entry": { historyEntry: types.HistoryRecord }; +  "safe-offer": { offer: types.OfferRecord }; +  "reserve-creation-info": { baseUrl: string }; +  "get-history": { }; +  "get-offer": { offerId: number } +  "get-currencies": { }; +  "update-currency": { currencyRecord: types.CurrencyRecord }; +  "get-reserves": { exchangeBaseUrl: string }; +  "get-payback-reserves": { }; +  "withdraw-payback-reserve": { reservePub: string }; +  "get-precoins": { exchangeBaseUrl: string }; +  "get-denoms": { exchangeBaseUrl: string }; +  "payback-coin": { coinPub: string }; +  "payment-failed": { contractTermsHash: string }; +  "payment-succeeded": { contractTermsHash: string; merchantSig: string }; +} + +export type MessageType = keyof MessageMap; + +export class Message<T extends MessageType> { +  constructor (public type: T, public detail: MessageMap[T]) { +  } +} diff --git a/src/webex/notify.ts b/src/webex/notify.ts index a7796cc8f..9823c5bd2 100644 --- a/src/webex/notify.ts +++ b/src/webex/notify.ts @@ -27,6 +27,8 @@   */  import URI = require("urijs"); +import wxApi = require("./wxApi"); +  declare var cloneInto: any;  let logVerbose: boolean = false; @@ -40,29 +42,12 @@ if (document.documentElement.getAttribute("data-taler-nojs")) {    document.dispatchEvent(new Event("taler-probe-result"));  } -  interface Handler {    type: string;    listener: (e: CustomEvent) => void|Promise<void>;  }  const handlers: Handler[] = []; -function hashContract(contract: string): Promise<string> { -  const walletHashContractMsg = { -    detail: {contract}, -    type: "hash-contract", -  }; -  return new Promise<string>((resolve, reject) => { -    chrome.runtime.sendMessage(walletHashContractMsg, (resp: any) => { -      if (!resp.hash) { -        console.log("error", resp); -        reject(Error("hashing failed")); -      } -      resolve(resp.hash); -    }); -  }); -} -  function queryPayment(url: string): Promise<any> {    const walletMsg = {      detail: { url }, @@ -178,6 +163,8 @@ function handlePaymentResponse(walletResp: any) {        timeoutHandle = null;        err();      } +    timeoutHandle = window.setTimeout(onTimeout, 200); +      talerPaymentFailed(walletResp.H_contract).then(() => {        if (timeoutHandle !== null) {          clearTimeout(timeoutHandle); @@ -185,10 +172,8 @@ function handlePaymentResponse(walletResp: any) {        }        err();      }); -    timeoutHandle = window.setTimeout(onTimeout, 200);    } -    logVerbose && console.log("handling taler-notify-payment: ", walletResp);    // Payment timeout in ms.    let timeout_ms = 1000; @@ -353,7 +338,7 @@ async function processProposal(proposal: any) {      return;    } -  const contractHash = await hashContract(proposal.data); +  const contractHash = await wxApi.hashContract(proposal.data);    if (contractHash !== proposal.hash) {      console.error("merchant-supplied contract hash is wrong"); @@ -488,7 +473,7 @@ function registerHandlers() {    addHandler("taler-query-id", (msg: any, sendResponse: any) => { -    // FIXME: maybe include this info in taoer-probe? +    // FIXME: maybe include this info in taler-probe?      sendResponse({id: chrome.runtime.id});    }); @@ -518,46 +503,21 @@ function registerHandlers() {      window.location.href = redirectUrl;    }); -  addHandler("taler-confirm-reserve", (msg: any, sendResponse: any) => { -    const walletMsg = { -      detail: { -        reservePub: msg.reserve_pub, -      }, -      type: "confirm-reserve", -    }; -    chrome.runtime.sendMessage(walletMsg, (resp) => { -      sendResponse(); -    }); -  }); - - -  addHandler("taler-confirm-contract", async(msg: any) => { -    if (!msg.contract_wrapper) { -      console.error("contract wrapper missing"); +  addHandler("taler-confirm-reserve", async (msg: any, sendResponse: any) => { +    const reservePub = msg.reserve_pub; +    if (typeof reservePub !== "string") { +      console.error("taler-confirm-reserve expects parameter reserve_pub of type 'string'");        return;      } - -    const proposal = msg.contract_wrapper; - -    processProposal(proposal); +    await wxApi.confirmReserve(msg.reserve_pub); +    sendResponse();    });    addHandler("taler-pay", async(msg: any, sendResponse: any) => {      const resp = await talerPay(msg);      sendResponse(resp);    }); - -  addHandler("taler-payment-failed", async(msg: any, sendResponse: any) => { -    await talerPaymentFailed(msg.H_contract); -    sendResponse(); -  }); - -  addHandler("taler-payment-succeeded", async(msg: any, sendResponse: any) => { -    await talerPaymentSucceeded(msg); -    sendResponse(); -  });  }  logVerbose && console.log("loading Taler content script");  init(); - diff --git a/src/webex/pages/popup.tsx b/src/webex/pages/popup.tsx index c62a6f8af..54e4f3e2d 100644 --- a/src/webex/pages/popup.tsx +++ b/src/webex/pages/popup.tsx @@ -30,13 +30,11 @@ import * as i18n from "../../i18n";  import {    AmountJson,    Amounts, +  HistoryLevel, +  HistoryRecord,    WalletBalance,    WalletBalanceEntry,  } from "../../types"; -import { -  HistoryLevel, -  HistoryRecord, -} from "../../wallet";  import { abbrev } from "../renderHtml"; diff --git a/src/webex/wxApi.ts b/src/webex/wxApi.ts index e4684135b..248cb04b5 100644 --- a/src/webex/wxApi.ts +++ b/src/webex/wxApi.ts @@ -37,27 +37,6 @@ import {  } from "../types"; -/** - * Query the wallet for the coins that would be used to withdraw - * from a given reserve. - */ -export function getReserveCreationInfo(baseUrl: string, -                                       amount: AmountJson): Promise<ReserveCreationInfo> { -  const m = { type: "reserve-creation-info", detail: { baseUrl, amount } }; -  return new Promise<ReserveCreationInfo>((resolve, reject) => { -    chrome.runtime.sendMessage(m, (resp) => { -      if (resp.error) { -        console.error("error response", resp); -        const e = Error("call to reserve-creation-info failed"); -        (e as any).errorResponse = resp; -        reject(e); -        return; -      } -      resolve(resp); -    }); -  }); -} -  async function callBackend(type: string, detail?: any): Promise<any> {    return new Promise<any>((resolve, reject) => { @@ -73,34 +52,44 @@ async function callBackend(type: string, detail?: any): Promise<any> {  /** + * Query the wallet for the coins that would be used to withdraw + * from a given reserve. + */ +export function getReserveCreationInfo(baseUrl: string, +                                       amount: AmountJson): Promise<ReserveCreationInfo> { +  return callBackend("reserve-creation-info", { baseUrl, amount }); +} + + +/**   * Get all exchanges the wallet knows about.   */ -export async function getExchanges(): Promise<ExchangeRecord[]> { -  return await callBackend("get-exchanges"); +export function getExchanges(): Promise<ExchangeRecord[]> { +  return callBackend("get-exchanges");  }  /**   * Get all currencies the exchange knows about.   */ -export async function getCurrencies(): Promise<CurrencyRecord[]> { -  return await callBackend("get-currencies"); +export function getCurrencies(): Promise<CurrencyRecord[]> { +  return callBackend("get-currencies");  }  /**   * Get information about a specific currency.   */ -export async function getCurrency(name: string): Promise<CurrencyRecord|null> { -  return await callBackend("currency-info", {name}); +export function getCurrency(name: string): Promise<CurrencyRecord|null> { +  return callBackend("currency-info", {name});  }  /**   * Get information about a specific exchange.   */ -export async function getExchangeInfo(baseUrl: string): Promise<ExchangeRecord> { -  return await callBackend("exchange-info", {baseUrl}); +export function getExchangeInfo(baseUrl: string): Promise<ExchangeRecord> { +  return callBackend("exchange-info", {baseUrl});  } @@ -108,72 +97,72 @@ export async function getExchangeInfo(baseUrl: string): Promise<ExchangeRecord>   * Replace an existing currency record with the one given.  The currency to   * replace is specified inside the currency record.   */ -export async function updateCurrency(currencyRecord: CurrencyRecord): Promise<void> { -  return await callBackend("update-currency", { currencyRecord }); +export function updateCurrency(currencyRecord: CurrencyRecord): Promise<void> { +  return callBackend("update-currency", { currencyRecord });  }  /**   * Get all reserves the wallet has at an exchange.   */ -export async function getReserves(exchangeBaseUrl: string): Promise<ReserveRecord[]> { -  return await callBackend("get-reserves", { exchangeBaseUrl }); +export function getReserves(exchangeBaseUrl: string): Promise<ReserveRecord[]> { +  return callBackend("get-reserves", { exchangeBaseUrl });  }  /**   * Get all reserves for which a payback is available.   */ -export async function getPaybackReserves(): Promise<ReserveRecord[]> { -  return await callBackend("get-payback-reserves"); +export function getPaybackReserves(): Promise<ReserveRecord[]> { +  return callBackend("get-payback-reserves");  }  /**   * Withdraw the payback that is available for a reserve.   */ -export async function withdrawPaybackReserve(reservePub: string): Promise<ReserveRecord[]> { -  return await callBackend("withdraw-payback-reserve", { reservePub }); +export function withdrawPaybackReserve(reservePub: string): Promise<ReserveRecord[]> { +  return callBackend("withdraw-payback-reserve", { reservePub });  }  /**   * Get all coins withdrawn from the given exchange.   */ -export async function getCoins(exchangeBaseUrl: string): Promise<CoinRecord[]> { -  return await callBackend("get-coins", { exchangeBaseUrl }); +export function getCoins(exchangeBaseUrl: string): Promise<CoinRecord[]> { +  return callBackend("get-coins", { exchangeBaseUrl });  }  /**   * Get all precoins withdrawn from the given exchange.   */ -export async function getPreCoins(exchangeBaseUrl: string): Promise<PreCoinRecord[]> { -  return await callBackend("get-precoins", { exchangeBaseUrl }); +export function getPreCoins(exchangeBaseUrl: string): Promise<PreCoinRecord[]> { +  return callBackend("get-precoins", { exchangeBaseUrl });  }  /**   * Get all denoms offered by the given exchange.   */ -export async function getDenoms(exchangeBaseUrl: string): Promise<DenominationRecord[]> { -  return await callBackend("get-denoms", { exchangeBaseUrl }); +export function getDenoms(exchangeBaseUrl: string): Promise<DenominationRecord[]> { +  return callBackend("get-denoms", { exchangeBaseUrl });  }  /**   * Start refreshing a coin.   */ -export async function refresh(coinPub: string): Promise<void> { -  return await callBackend("refresh-coin", { coinPub }); +export function refresh(coinPub: string): Promise<void> { +  return callBackend("refresh-coin", { coinPub });  }  /**   * Request payback for a coin.  Only works for non-refreshed coins.   */ -export async function payback(coinPub: string): Promise<void> { -  return await callBackend("payback-coin", { coinPub }); +export function payback(coinPub: string): Promise<void> { +  return callBackend("payback-coin", { coinPub });  }  /** @@ -181,20 +170,41 @@ export async function payback(coinPub: string): Promise<void> {   * Note that the numeric offer id is not to be confused with   * the string order_id from the contract terms.   */ -export async function getOffer(offerId: number) { -  return await callBackend("get-offer", { offerId }); +export function getOffer(offerId: number) { +  return callBackend("get-offer", { offerId });  }  /**   * Check if payment is possible or already done.   */ -export async function checkPay(offer: OfferRecord): Promise<CheckPayResult> { -  return await callBackend("check-pay", { offer }); +export function checkPay(offer: OfferRecord): Promise<CheckPayResult> { +  return callBackend("check-pay", { offer });  }  /**   * Pay for an offer.   */ -export async function confirmPay(offer: OfferRecord): Promise<ConfirmPayResult> { -  return await callBackend("confirm-pay", { offer }); +export function confirmPay(offer: OfferRecord): Promise<ConfirmPayResult> { +  return callBackend("confirm-pay", { offer }); +} + +/** + * Hash a contract.  Throws if its not a valid contract. + */ +export function hashContract(contract: object): Promise<string> { +  return callBackend("confirm-pay", { contract }); +} + +/** + * Save an offer in the wallet. + */ +export function saveOffer(offer: object): Promise<void> { +  return callBackend("save-offer", { offer }); +} + +/** + * Mark a reserve as confirmed. + */ +export function confirmReserve(reservePub: string): Promise<void> { +  return callBackend("confirm-reserve", { reservePub });  } diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts index eaae41b9f..49f6e7112 100644 --- a/src/webex/wxBackend.ts +++ b/src/webex/wxBackend.ts @@ -44,6 +44,7 @@ import {  } from "../wallet";  import { ChromeBadge } from "./chromeBadge"; +  import URI = require("urijs");  import Port = chrome.runtime.Port;  import MessageSender = chrome.runtime.MessageSender; @@ -300,9 +301,10 @@ function makeHandlers(db: IDBDatabase,  async function dispatch(handlers: any, req: any, sender: any, sendResponse: any): Promise<void> {    if (!(req.type in handlers)) { -    console.error(`Request type ${JSON.stringify(req)} unknown, req ${req.type}`); +    console.error(`Request type ${req.type} unknown`); +    console.error(`Request was ${req}`);      try { -      sendResponse({ error: "request unknown" }); +      sendResponse({ error: "request unknown", requestType: req.type });      } catch (e) {        // might fail if tab disconnected      } diff --git a/tsconfig.json b/tsconfig.json index f4250a2c5..2ba62b510 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -50,6 +50,7 @@      "src/webex/background.ts",      "src/webex/chromeBadge.ts",      "src/webex/components.ts", +    "src/webex/messages.ts",      "src/webex/notify.ts",      "src/webex/pages/add-auditor.tsx",      "src/webex/pages/auditors.tsx", @@ -65,4 +66,4 @@      "src/webex/wxApi.ts",      "src/webex/wxBackend.ts"    ] -}
\ No newline at end of file +} | 
