gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-wallet-webex] branch master updated (c26ee93 -> 79a2


From: gnunet
Subject: [GNUnet-SVN] [taler-wallet-webex] branch master updated (c26ee93 -> 79a2eed)
Date: Wed, 26 Apr 2017 03:10:56 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a change to branch master
in repository wallet-webex.

    from c26ee93  Optimize production builds.
     new 9aab9fd  don't fail if we don't pass env to webpack
     new 79a2eed  remove dependency in taler-wallet-lib, implement pay 
signature check/storage

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 manifest.json                 |   1 -
 node_modules/.yarn-integrity  |   2 +-
 src/content_scripts/notify.ts | 768 +++++++++++++++++++++++++-----------------
 src/cryptoApi.ts              |   4 +
 src/cryptoWorker.ts           |  14 +
 src/emscriptif.ts             |  21 ++
 src/taler-wallet-lib.ts       |   1 -
 src/wallet.ts                 |   9 +-
 src/wxBackend.ts              |   6 +-
 tsconfig.json                 |   1 -
 web-common                    |   2 +-
 webpack.config.js             |   1 +
 12 files changed, 515 insertions(+), 315 deletions(-)
 delete mode 120000 src/taler-wallet-lib.ts

diff --git a/manifest.json b/manifest.json
index f59aac2..c93d49f 100644
--- a/manifest.json
+++ b/manifest.json
@@ -43,7 +43,6 @@
     {
       "matches": ["*://*/*"],
       "js": [
-        "src/taler-wallet-lib.js",
         "dist/contentScript-bundle.js"
       ],
       "run_at": "document_start"
diff --git a/node_modules/.yarn-integrity b/node_modules/.yarn-integrity
index a45758d..6d4c42d 100644
--- a/node_modules/.yarn-integrity
+++ b/node_modules/.yarn-integrity
@@ -1 +1 @@
-0dc42bcf25ec3d59c7bd394b1d9f751da1a3446ef6012260b277831cef6de2bf
\ No newline at end of file
+751d3ff225403bea12799f2c0ad32d26a0ff81a4f88821c8f1615d3ddc5a9533
\ No newline at end of file
diff --git a/src/content_scripts/notify.ts b/src/content_scripts/notify.ts
index 8a25dd5..a0f76cf 100644
--- a/src/content_scripts/notify.ts
+++ b/src/content_scripts/notify.ts
@@ -23,378 +23,530 @@
  */
 
 
-"use strict";
-
 import URI = require("urijs");
 
 declare var cloneInto: any;
 
-// Make sure we don't pollute the namespace too much.
-namespace TalerNotify {
-  const PROTOCOL_VERSION = 1;
+const PROTOCOL_VERSION = 1;
 
-  let logVerbose: boolean = false;
-  try {
-    logVerbose = !!localStorage.getItem("taler-log-verbose");
-  } catch (e) {
-    // can't read from local storage
-  }
+let logVerbose: boolean = false;
+try {
+  logVerbose = !!localStorage.getItem("taler-log-verbose");
+} catch (e) {
+  // can't read from local storage
+}
 
-  if (!taler) {
-    console.error("Taler wallet lib not included, HTTP 402 payments not" +
-                  " supported");
-  }
+if (document.documentElement.getAttribute("data-taler-nojs")) {
+  document.dispatchEvent(new Event("taler-probe-result"));
+}
 
-  if (document.documentElement.getAttribute("data-taler-nojs")) {
-    document.dispatchEvent(new Event("taler-probe-result"));
-  }
 
+function subst(url: string, H_contract: string) {
+  url = url.replace("${H_contract}", H_contract);
+  url = url.replace("${$}", "$");
+  return url;
+}
 
-  function subst(url: string, H_contract: string) {
-    url = url.replace("${H_contract}", H_contract);
-    url = url.replace("${$}", "$");
-    return url;
-  }
+interface Handler {
+  type: string;
+  listener: (e: CustomEvent) => void|Promise<void>;
+}
+const handlers: Handler[] = [];
+
+function hashContract(contract: string): Promise<string> {
+  let walletHashContractMsg = {
+    type: "hash-contract",
+    detail: {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);
+    });
+  });
+}
 
-  interface Handler {
-    type: string;
-    listener: (e: CustomEvent) => void|Promise<void>;
-  }
-  const handlers: Handler[] = [];
+function queryPayment(url: string): Promise<any> {
+  const walletMsg = {
+    type: "query-payment",
+    detail: { url },
+  };
+  return new Promise((resolve, reject) => {
+    chrome.runtime.sendMessage(walletMsg, (resp: any) => {
+      resolve(resp);
+    });
+  });
+}
 
-  function hashContract(contract: string): Promise<string> {
-    let walletHashContractMsg = {
-      type: "hash-contract",
-      detail: {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 putHistory(historyEntry: any): Promise<void> {
+  const walletMsg = {
+    type: "put-history-entry",
+    detail: {
+      historyEntry,
+    },
+  };
+  return new Promise<void>((resolve, reject) => {
+    chrome.runtime.sendMessage(walletMsg, (resp: any) => {
+      resolve();
     });
-  }
+  });
+}
 
-  function queryPayment(url: string): Promise<any> {
-    const walletMsg = {
-      type: "query-payment",
-      detail: { url },
-    };
-    return new Promise((resolve, reject) => {
-      chrome.runtime.sendMessage(walletMsg, (resp: any) => {
+function saveOffer(offer: any): Promise<number> {
+  const walletMsg = {
+    type: "save-offer",
+    detail: {
+      offer: {
+        contract: offer.data,
+        merchant_sig: offer.sig,
+        H_contract: offer.hash,
+        offer_time: new Date().getTime() / 1000
+      },
+    },
+  };
+  return new Promise<number>((resolve, reject) => {
+    chrome.runtime.sendMessage(walletMsg, (resp: any) => {
+      if (resp && resp.error) {
+        reject(resp);
+      } else {
         resolve(resp);
-      });
+      }
     });
+  });
+}
+
+
+
+
+let sheet: CSSStyleSheet|null;
+
+function initStyle() {
+  logVerbose && console.log("taking over styles");
+  const name = "taler-presence-stylesheet";
+  const content = "/* Taler stylesheet controlled by JS */";
+  let style = document.getElementById(name) as HTMLStyleElement|null; 
+  if (!style) {
+    style = document.createElement("style");
+    // Needed by WebKit
+    style.appendChild(document.createTextNode(content));
+    style.id = name;
+    document.head.appendChild(style);
+    sheet = style.sheet as CSSStyleSheet;
+  } else {
+    // We've taken over the stylesheet now,
+    // make it clear by clearing all the rules in it
+    // and making it obvious in the DOM.
+    if (style.tagName.toLowerCase() === "style") {
+      style.innerText = content;
+    }
+    if (!style.sheet) {
+      throw Error("taler-presence-stylesheet should be a style sheet (<link> 
or <style>)");
+    }
+    sheet = style.sheet as CSSStyleSheet;
+    while (sheet.cssRules.length > 0) {
+      sheet.deleteRule(0);
+    }
   }
+}
 
-  function putHistory(historyEntry: any): Promise<void> {
-    const walletMsg = {
-      type: "put-history-entry",
-      detail: {
-        historyEntry,
-      },
-    };
-    return new Promise<void>((resolve, reject) => {
-      chrome.runtime.sendMessage(walletMsg, (resp: any) => {
-        resolve();
-      });
-    });
+
+function setStyles(installed: boolean) {
+  if (!sheet || !sheet.cssRules) {
+    return;
+  }
+  while (sheet.cssRules.length > 0) {
+    sheet.deleteRule(0);
   }
+  if (installed) {
+    sheet.insertRule(".taler-installed-hide { display: none; }", 0);
+    sheet.insertRule(".taler-probed-hide { display: none; }", 0);
+  } else {
+    sheet.insertRule(".taler-installed-show { display: none; }", 0);
+  }
+}
 
-  function saveOffer(offer: any): Promise<number> {
-    const walletMsg = {
-      type: "save-offer",
-      detail: {
-        offer: {
-          contract: offer.data,
-          merchant_sig: offer.sig,
-          H_contract: offer.hash,
-          offer_time: new Date().getTime() / 1000
-        },
-      },
-    };
-    return new Promise<number>((resolve, reject) => {
-      chrome.runtime.sendMessage(walletMsg, (resp: any) => {
-        if (resp && resp.error) {
-          reject(resp);
-        } else {
-          resolve(resp);
-        }
-      });
-    });
+
+
+function handlePaymentResponse(walletResp: any) {
+  /**
+   * Handle a failed payment.
+   *
+   * Try to notify the wallet first, before we show a potentially
+   * synchronous error message (such as an alert) or leave the page.
+   */
+  function handleFailedPayment(r: XMLHttpRequest) {
+    let timeoutHandle: number|null = null;
+    function err() {
+      // FIXME: proper error reporting!
+      console.log("pay-failed", {status: r.status, response: r.responseText});
+    }
+    function onTimeout() {
+      timeoutHandle = null
+      err();
+    }
+    talerPaymentFailed(walletResp.H_contract).then(() => {
+      if (timeoutHandle != null) {
+        clearTimeout(timeoutHandle);
+        timeoutHandle = null;
+      }
+      err();
+    })
+    timeoutHandle = setTimeout(onTimeout, 200);
   }
 
-  function init() {
-    chrome.runtime.sendMessage({type: "get-tab-cookie"}, (resp) => {
-      if (chrome.runtime.lastError) {
-        logVerbose && console.log("extension not yet ready");
-        window.setTimeout(init, 200);
+
+  logVerbose && console.log("handling taler-notify-payment: ", walletResp);
+  // Payment timeout in ms.
+  let timeout_ms = 1000;
+  // Current request.
+  let r: XMLHttpRequest|null;
+  let timeoutHandle: number|null = null;
+  function sendPay() {
+    r = new XMLHttpRequest();
+    r.open("post", walletResp.contract.pay_url);
+    r.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
+    r.send(JSON.stringify(walletResp.payReq));
+    r.onload = function() {
+      if (!r) {
         return;
       }
-      registerHandlers();
-      // Hack to know when the extension is unloaded
-      let port = chrome.runtime.connect();
-
-      port.onDisconnect.addListener(() => {
-        logVerbose && console.log("chrome runtime disconnected, removing 
handlers");
-        for (let handler of handlers) {
-          document.removeEventListener(handler.type, handler.listener);
-        }
-      });
+      switch (r.status) {
+        case 200:
+          const merchantResp = JSON.parse(r.responseText);
+          logVerbose && console.log("got success from pay_url");
+          talerPaymentSucceeded({H_contract: walletResp.H_contract, 
merchantSig: merchantResp.sig}).then(() => {
+            let nextUrl = walletResp.contract.fulfillment_url;
+            logVerbose && console.log("taler-payment-succeeded done, going 
to", nextUrl);
+            window.location.href = nextUrl;
+            window.location.reload(true);
+          });
+          break;
+        default:
+          handleFailedPayment(r);
+          break;
+      }
+      r = null;
+      if (timeoutHandle != null) {
+        clearTimeout(timeoutHandle!);
+        timeoutHandle = null;
+      }
+    };
+    function retry() {
+      if (r) {
+        r.abort();
+        r = null;
+      }
+      timeout_ms = Math.min(timeout_ms * 2, 10 * 1000);
+      logVerbose && console.log("sendPay timed out, retrying in ", timeout_ms, 
"ms");
+      sendPay();
+    }
+    timeoutHandle = setTimeout(retry, timeout_ms);
+  }
+  sendPay();
+}
 
-      if (resp && resp.type == "pay") {
-        logVerbose && console.log("doing taler.pay with", resp.payDetail);
-        taler.internalPay(resp.payDetail);
-        document.documentElement.style.visibility = "hidden";
+
+function init() {
+  chrome.runtime.sendMessage({type: "get-tab-cookie"}, (resp) => {
+    if (chrome.runtime.lastError) {
+      logVerbose && console.log("extension not yet ready");
+      window.setTimeout(init, 200);
+      return;
+    }
+    initStyle();
+    setStyles(true);
+    registerHandlers();
+    // Hack to know when the extension is unloaded
+    let port = chrome.runtime.connect();
+
+    port.onDisconnect.addListener(() => {
+      logVerbose && console.log("chrome runtime disconnected, removing 
handlers");
+      setStyles(false);
+      for (let handler of handlers) {
+        document.removeEventListener(handler.type, handler.listener);
       }
     });
-  }
 
-  logVerbose && console.log("loading Taler content script");
-  init();
+    if (resp && resp.type == "pay") {
+      logVerbose && console.log("doing taler.pay with", resp.payDetail);
+      talerPay(resp.payDetail).then(handlePaymentResponse);
+      document.documentElement.style.visibility = "hidden";
+    }
+  });
+}
 
-  interface HandlerFn {
-    (detail: any, sendResponse: (msg: any) => void): void;
-  }
+interface HandlerFn {
+  (detail: any, sendResponse: (msg: any) => void): void;
+}
 
-  function generateNonce(): Promise<string> {
-    const walletMsg = {
-      type: "generate-nonce",
-    };
-    return new Promise<string>((resolve, reject) => {
-      chrome.runtime.sendMessage(walletMsg, (resp: any) => {
-        resolve(resp);
-      });
+function generateNonce(): Promise<string> {
+  const walletMsg = {
+    type: "generate-nonce",
+  };
+  return new Promise<string>((resolve, reject) => {
+    chrome.runtime.sendMessage(walletMsg, (resp: any) => {
+      resolve(resp);
     });
-  }
+  });
+}
 
-  function downloadContract(url: string, nonce: string): Promise<any> {
-    let parsed_url = new URI(url);
-    url = parsed_url.setQuery({nonce}).href();
-    // FIXME: include and check nonce!
-    return new Promise((resolve, reject) => {
-      const contract_request = new XMLHttpRequest();
-      console.log("downloading contract from '" + url + "'")
-      contract_request.open("GET", url, true);
-      contract_request.onload = function (e) {
-        if (contract_request.readyState == 4) {
-          if (contract_request.status == 200) {
-            console.log("response text:",
-                        contract_request.responseText);
-            var contract_wrapper = JSON.parse(contract_request.responseText);
-            if (!contract_wrapper) {
-              console.error("response text was invalid json");
-              let detail = {hint: "invalid json", status: 
contract_request.status, body: contract_request.responseText};
-              reject(detail);
-              return;
-            }
-            resolve(contract_wrapper);
-          } else {
-            let detail = {hint: "contract download failed", status: 
contract_request.status, body: contract_request.responseText};
+function downloadContract(url: string, nonce: string): Promise<any> {
+  let parsed_url = new URI(url);
+  url = parsed_url.setQuery({nonce}).href();
+  // FIXME: include and check nonce!
+  return new Promise((resolve, reject) => {
+    const contract_request = new XMLHttpRequest();
+    console.log("downloading contract from '" + url + "'")
+    contract_request.open("GET", url, true);
+    contract_request.onload = function (e) {
+      if (contract_request.readyState == 4) {
+        if (contract_request.status == 200) {
+          console.log("response text:",
+                      contract_request.responseText);
+          var contract_wrapper = JSON.parse(contract_request.responseText);
+          if (!contract_wrapper) {
+            console.error("response text was invalid json");
+            let detail = {hint: "invalid json", status: 
contract_request.status, body: contract_request.responseText};
             reject(detail);
             return;
           }
+          resolve(contract_wrapper);
+        } else {
+          let detail = {hint: "contract download failed", status: 
contract_request.status, body: contract_request.responseText};
+          reject(detail);
+          return;
         }
-      };
-      contract_request.onerror = function (e) {
-        let detail = {hint: "contract download failed", status: 
contract_request.status, body: contract_request.responseText};
-        reject(detail);
-        return;
-      };
-      contract_request.send();
-    });
+      }
+    };
+    contract_request.onerror = function (e) {
+      let detail = {hint: "contract download failed", status: 
contract_request.status, body: contract_request.responseText};
+      reject(detail);
+      return;
+    };
+    contract_request.send();
+  });
+}
+
+async function processProposal(proposal: any) {
+  if (!proposal.data) {
+    console.error("field proposal.data field missing");
+    return;
   }
 
-  async function processProposal(proposal: any) {
-    if (!proposal.data) {
-      console.error("field proposal.data field missing");
-      return;
+  if (!proposal.hash) {
+    console.error("proposal.hash field missing");
+    return;
+  }
+
+  let contractHash = await hashContract(proposal.data);
+
+  if (contractHash != proposal.hash) {
+    console.error("merchant-supplied contract hash is wrong");
+    return;
+  }
+
+  let merchantName = "(unknown)";
+  try {
+    merchantName = proposal.data.merchant.name;
+  } catch (e) {
+    // bad contract / name not included
+  }
+
+  let historyEntry = {
+    timestamp: (new Date).getTime(),
+    subjectId: `contract-${contractHash}`,
+    type: "offer-contract",
+    detail: {
+      contractHash,
+      merchantName,
     }
+  };
+  await putHistory(historyEntry);
+  let offerId = await saveOffer(proposal);
+
+  const uri = new URI(chrome.extension.getURL(
+    "/src/pages/confirm-contract.html"));
+  const params = {
+    offerId: offerId.toString(),
+  };
+  const target = uri.query(params).href();
+  document.location.replace(target);
+}
 
-    if (!proposal.hash) {
-      console.error("proposal.hash field missing");
+function talerPay(msg: any): Promise<any> {
+  return new Promise(async(resolve, reject) => {
+    // current URL without fragment
+    let url = new URI(document.location.href).fragment("").href();
+    let res = await queryPayment(url);
+    logVerbose && console.log("taler-pay: got response", res);
+    if (res && res.payReq) {
+      resolve(res);
       return;
     }
-
-    let contractHash = await hashContract(proposal.data);
-
-    if (contractHash != proposal.hash) {
-      console.error("merchant-supplied contract hash is wrong");
+    if (msg.contract_url) {
+      let nonce = await generateNonce();
+      let proposal = await downloadContract(msg.contract_url, nonce);
+      if (proposal.data.nonce != nonce) {
+        console.error("stale contract");
+        return;
+      }
+      await processProposal(proposal);
       return;
     }
 
-    let merchantName = "(unknown)";
-    try {
-      merchantName = proposal.data.merchant.name;
-    } catch (e) {
-      // bad contract / name not included
+    if (msg.offer_url) {
+      document.location.href = msg.offer_url;
+      return;
     }
 
-    let historyEntry = {
-      timestamp: (new Date).getTime(),
-      subjectId: `contract-${contractHash}`,
-      type: "offer-contract",
-      detail: {
-        contractHash,
-        merchantName,
-      }
-    };
-    await putHistory(historyEntry);
-    let offerId = await saveOffer(proposal);
+    console.log("can't proceed with payment, no way to get contract 
specified");
+  });
+}
 
-    const uri = new URI(chrome.extension.getURL(
-      "/src/pages/confirm-contract.html"));
-    const params = {
-      offerId: offerId.toString(),
+function talerPaymentFailed(H_contract: string) {
+  return new Promise(async(resolve, reject) => {
+    const walletMsg = {
+      type: "payment-failed",
+      detail: {
+        contractHash: H_contract
+      },
     };
-    const target = uri.query(params).href();
-    document.location.replace(target);
-  }
+    chrome.runtime.sendMessage(walletMsg, (resp) => {
+      resolve();
+    });
+  });
+}
 
-  function registerHandlers() {
-    /**
-     * Add a handler for a DOM event, which automatically
-     * handles adding sequence numbers to responses.
-     */
-    function addHandler(type: string, handler: HandlerFn) {
-      let handlerWrap = (e: CustomEvent) => {
-        if (e.type != type) {
-          throw Error(`invariant violated`);
-        }
-        let callId: number|undefined = undefined;
-        if (e.detail && e.detail.callId != undefined) {
-          callId = e.detail.callId;
-        }
-        let responder = (msg?: any) => {
-          let fullMsg = Object.assign({}, msg, {callId});
-          let opts = { detail: fullMsg };
-          if ("function" == typeof cloneInto) {
-            opts = cloneInto(opts, document.defaultView);
-          }
-          let evt = new CustomEvent(type + "-result", opts);
-          document.dispatchEvent(evt);
-        };
-        handler(e.detail, responder);
-      };
-      document.addEventListener(type, handlerWrap);
-      handlers.push({type, listener: handlerWrap});
+function talerPaymentSucceeded(msg: any) {
+  return new Promise((resolve, reject) => {
+    if (!msg.H_contract) {
+      console.error("H_contract missing in taler-payment-succeeded");
+      return;
     }
-
-
-    addHandler("taler-query-id", (msg: any, sendResponse: any) => {
-      // FIXME: maybe include this info in taoer-probe?
-      sendResponse({id: chrome.runtime.id})
+    if (!msg.merchantSig) {
+      console.error("merchantSig missing in taler-payment-succeeded");
+      return;
+    }
+    logVerbose && console.log("got taler-payment-succeeded");
+    const walletMsg = {
+      type: "payment-succeeded",
+      detail: {
+        merchantSig: msg.merchantSig,
+        contractHash: msg.H_contract,
+      },
+    };
+    chrome.runtime.sendMessage(walletMsg, (resp) => {
+      resolve();
     });
+  });
+}
 
-    addHandler("taler-probe", (msg: any, sendResponse: any) => {
-      sendResponse();
-    });
 
-    addHandler("taler-create-reserve", (msg: any) => {
-      let params = {
-        amount: JSON.stringify(msg.amount),
-        callback_url: new URI(msg.callback_url)
-          .absoluteTo(document.location.href),
-        bank_url: document.location.href,
-        wt_types: JSON.stringify(msg.wt_types),
-        suggested_exchange_url: msg.suggested_exchange_url,
+function registerHandlers() {
+  /**
+   * Add a handler for a DOM event, which automatically
+   * handles adding sequence numbers to responses.
+   */
+  function addHandler(type: string, handler: HandlerFn) {
+    let handlerWrap = (e: CustomEvent) => {
+      if (e.type != type) {
+        throw Error(`invariant violated`);
+      }
+      let callId: number|undefined = undefined;
+      if (e.detail && e.detail.callId != undefined) {
+        callId = e.detail.callId;
+      }
+      let responder = (msg?: any) => {
+        let fullMsg = Object.assign({}, msg, {callId});
+        let opts = { detail: fullMsg };
+        if ("function" == typeof cloneInto) {
+          opts = cloneInto(opts, document.defaultView);
+        }
+        let evt = new CustomEvent(type + "-result", opts);
+        document.dispatchEvent(evt);
       };
-      let uri = new 
URI(chrome.extension.getURL("/src/pages/confirm-create-reserve.html"));
-      let redirectUrl = uri.query(params).href();
-      window.location.href = redirectUrl;
-    });
+      handler(e.detail, responder);
+    };
+    document.addEventListener(type, handlerWrap);
+    handlers.push({type, listener: handlerWrap});
+  }
 
-    addHandler("taler-add-auditor", (msg: any) => {
-      let params = {
-        req: JSON.stringify(msg),
-      };
-      let uri = new 
URI(chrome.extension.getURL("/src/pages/add-auditor.html"));
-      let redirectUrl = uri.query(params).href();
-      window.location.href = redirectUrl;
-    });
 
-    addHandler("taler-confirm-reserve", (msg: any, sendResponse: any) => {
-      let walletMsg = {
-        type: "confirm-reserve",
-        detail: {
-          reservePub: msg.reserve_pub
-        }
-      };
-      chrome.runtime.sendMessage(walletMsg, (resp) => {
-        sendResponse();
-      });
-    });
+  addHandler("taler-query-id", (msg: any, sendResponse: any) => {
+    // FIXME: maybe include this info in taoer-probe?
+    sendResponse({id: chrome.runtime.id})
+  });
 
+  addHandler("taler-probe", (msg: any, sendResponse: any) => {
+    sendResponse();
+  });
 
-    addHandler("taler-confirm-contract", async(msg: any) => {
-      if (!msg.contract_wrapper) {
-        console.error("contract wrapper missing");
-        return;
+  addHandler("taler-create-reserve", (msg: any) => {
+    let params = {
+      amount: JSON.stringify(msg.amount),
+      callback_url: new URI(msg.callback_url)
+        .absoluteTo(document.location.href),
+      bank_url: document.location.href,
+      wt_types: JSON.stringify(msg.wt_types),
+      suggested_exchange_url: msg.suggested_exchange_url,
+    };
+    let uri = new 
URI(chrome.extension.getURL("/src/pages/confirm-create-reserve.html"));
+    let redirectUrl = uri.query(params).href();
+    window.location.href = redirectUrl;
+  });
+
+  addHandler("taler-add-auditor", (msg: any) => {
+    let params = {
+      req: JSON.stringify(msg),
+    };
+    let uri = new URI(chrome.extension.getURL("/src/pages/add-auditor.html"));
+    let redirectUrl = uri.query(params).href();
+    window.location.href = redirectUrl;
+  });
+
+  addHandler("taler-confirm-reserve", (msg: any, sendResponse: any) => {
+    let walletMsg = {
+      type: "confirm-reserve",
+      detail: {
+        reservePub: msg.reserve_pub
       }
+    };
+    chrome.runtime.sendMessage(walletMsg, (resp) => {
+      sendResponse();
+    });
+  });
 
-      const proposal = msg.contract_wrapper;
 
-      processProposal(proposal);
-    });
+  addHandler("taler-confirm-contract", async(msg: any) => {
+    if (!msg.contract_wrapper) {
+      console.error("contract wrapper missing");
+      return;
+    }
 
-    addHandler("taler-pay", async(msg: any, sendResponse: any) => {
-      // current URL without fragment
-      let url = new URI(document.location.href).fragment("").href();
-      let res = await queryPayment(url);
-      logVerbose && console.log("taler-pay: got response", res);
-      if (res && res.payReq) {
-        sendResponse(res);
-        return;
-      }
-      if (msg.contract_url) {
-        let nonce = await generateNonce();
-        let proposal = await downloadContract(msg.contract_url, nonce);
-        if (proposal.data.nonce != nonce) {
-          console.error("stale contract");
-          return;
-        }
-        await processProposal(proposal);
-        return;
-      }
+    const proposal = msg.contract_wrapper;
 
-      if (msg.offer_url) {
-        document.location.href = msg.offer_url;
-        return;
-      }
+    processProposal(proposal);
+  });
 
-      console.log("can't proceed with payment, no way to get contract 
specified");
-    });
+  addHandler("taler-pay", async(msg: any, sendResponse: any) => {
+    let resp = await talerPay(msg);
+    sendResponse(resp);
+  });
 
-    addHandler("taler-payment-failed", (msg: any, sendResponse: any) => {
-      const walletMsg = {
-        type: "payment-failed",
-        detail: {
-          contractHash: msg.H_contract
-        },
-      };
-      chrome.runtime.sendMessage(walletMsg, (resp) => {
-        sendResponse();
-      })
-    });
+  addHandler("taler-payment-failed", async(msg: any, sendResponse: any) => {
+    await talerPaymentFailed(msg.H_contract);
+    sendResponse();
+  });
 
-    addHandler("taler-payment-succeeded", (msg: any, sendResponse: any) => {
-      if (!msg.H_contract) {
-        console.error("H_contract missing in taler-payment-succeeded");
-        return;
-      }
-      logVerbose && console.log("got taler-payment-succeeded");
-      const walletMsg = {
-        type: "payment-succeeded",
-        detail: {
-          contractHash: msg.H_contract,
-        },
-      };
-      chrome.runtime.sendMessage(walletMsg, (resp) => {
-        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/cryptoApi.ts b/src/cryptoApi.ts
index 672b90d..98fc2c6 100644
--- a/src/cryptoApi.ts
+++ b/src/cryptoApi.ts
@@ -235,6 +235,10 @@ export class CryptoApi {
     return this.doRpc<boolean>("isValidDenom", 2, denom, masterPub);
   }
 
+  isValidPaymentSignature(sig: string, contractHash: string, merchantPub: 
string) {
+    return this.doRpc<PayCoinInfo>("isValidPaymentSignature", 1, sig, 
contractHash, merchantPub);
+  }
+
   signDeposit(offer: OfferRecord,
               cds: CoinWithDenom[]): Promise<PayCoinInfo> {
     return this.doRpc<PayCoinInfo>("signDeposit", 3, offer, cds);
diff --git a/src/cryptoWorker.ts b/src/cryptoWorker.ts
index 0abcb36..cb7bee4 100644
--- a/src/cryptoWorker.ts
+++ b/src/cryptoWorker.ts
@@ -97,6 +97,20 @@ namespace RpcFunctions {
   }
 
 
+  export function isValidPaymentSignature(sig: string, contractHash: string, 
merchantPub: string) {
+    let p = new native.PaymentSignaturePS({
+      contract_hash: native.HashCode.fromCrock(contractHash),
+    });
+    let nativeSig = new native.EddsaSignature();
+    nativeSig.loadCrock(sig);
+    let nativePub = native.EddsaPublicKey.fromCrock(merchantPub);
+    return native.eddsaVerify(native.SignaturePurpose.MERCHANT_PAYMENT_OK,
+                              p.toPurpose(),
+                              nativeSig,
+                              nativePub);
+  }
+
+
   export function isValidDenom(denom: DenominationRecord,
                                masterPub: string): boolean {
     let p = new native.DenominationKeyValidityPS({
diff --git a/src/emscriptif.ts b/src/emscriptif.ts
index 0b3f2ae..3a34f64 100644
--- a/src/emscriptif.ts
+++ b/src/emscriptif.ts
@@ -206,6 +206,7 @@ export enum SignaturePurpose {
   MASTER_DENOMINATION_KEY_VALIDITY = 1025,
   WALLET_COIN_MELT = 1202,
   TEST = 4242,
+  MERCHANT_PAYMENT_OK = 1104,
 }
 
 
@@ -1134,6 +1135,26 @@ export class DenominationKeyValidityPS extends 
SignatureStruct {
   }
 }
 
+export interface PaymentSignaturePS_args {
+  contract_hash: HashCode;
+}
+
+export class PaymentSignaturePS extends SignatureStruct {
+  constructor(w: PaymentSignaturePS_args) {
+    super(w);
+  }
+
+  purpose() {
+    return SignaturePurpose.MERCHANT_PAYMENT_OK;
+  }
+
+  fieldTypes() {
+    return [
+      ["contract_hash", HashCode],
+    ];
+  }
+}
+
 
 export class RsaPublicKey extends MallocArenaObject {
   static fromCrock(s: string): RsaPublicKey {
diff --git a/src/taler-wallet-lib.ts b/src/taler-wallet-lib.ts
deleted file mode 120000
index 20e5993..0000000
--- a/src/taler-wallet-lib.ts
+++ /dev/null
@@ -1 +0,0 @@
-../web-common/taler-wallet-lib.ts
\ No newline at end of file
diff --git a/src/wallet.ts b/src/wallet.ts
index a809b94..5104615 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -1787,7 +1787,7 @@ export class Wallet {
   }
 
 
-  async paymentSucceeded(contractHash: string): Promise<any> {
+  async paymentSucceeded(contractHash: string, merchantSig: string): 
Promise<any> {
     const doPaymentSucceeded = async() => {
       let t = await this.q().get<TransactionRecord>(Stores.transactions,
                                                     contractHash);
@@ -1795,6 +1795,13 @@ export class Wallet {
         console.error("contract not found");
         return;
       }
+      let merchantPub = t.contract.merchant_pub;
+      let valid = this.cryptoApi.isValidPaymentSignature(merchantSig, 
contractHash, merchantPub);
+      if (!valid) {
+        console.error("merchant payment signature invalid");
+        // FIXME: properly display error
+        return;
+      }
       t.finished = true;
       let modifiedCoins: CoinRecord[] = [];
       for (let pc of t.payReq.coins) {
diff --git a/src/wxBackend.ts b/src/wxBackend.ts
index 1aa10ce..984cad2 100644
--- a/src/wxBackend.ts
+++ b/src/wxBackend.ts
@@ -254,10 +254,14 @@ function makeHandlers(db: IDBDatabase,
     },
     ["payment-succeeded"]: function (detail, sender) {
       let contractHash = detail.contractHash;
+      let merchantSig = detail.merchantSig;
       if (!contractHash) {
         return Promise.reject(Error("contractHash missing"));
       }
-      return wallet.paymentSucceeded(contractHash);
+      if (!merchantSig) {
+        return Promise.reject(Error("merchantSig missing"));
+      }
+      return wallet.paymentSucceeded(contractHash, merchantSig);
     },
   };
 }
diff --git a/tsconfig.json b/tsconfig.json
index 93c7fb1..8dc8cb7 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -48,7 +48,6 @@
     "src/pages/tree.tsx",
     "src/query.ts",
     "src/renderHtml.tsx",
-    "src/taler-wallet-lib.ts",
     "src/types-test.ts",
     "src/types.ts",
     "src/wallet-test.ts",
diff --git a/web-common b/web-common
index d7e0135..a8bff2e 160000
--- a/web-common
+++ b/web-common
@@ -1 +1 @@
-Subproject commit d7e013594d15388b1a7342a44a0e9c8d4ecca82d
+Subproject commit a8bff2e27b89feb3696cf0e3a49fc00155d92de5
diff --git a/webpack.config.js b/webpack.config.js
index e191553..2a1f13d 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -4,6 +4,7 @@ const merge = require('webpack-merge');
 
 
 module.exports = function (env) {
+  env = env || {};
   const base = {
     output: {
       filename: '[name]-bundle.js',

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]