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: support code fo


From: gnunet
Subject: [GNUnet-SVN] [taler-wallet-webex] branch master updated: support code for NFC tunneling
Date: Thu, 22 Aug 2019 23:36:46 +0200

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

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

The following commit(s) were added to refs/heads/master by this push:
     new 0032ff9f support code for NFC tunneling
0032ff9f is described below

commit 0032ff9f3680782d4d8f287e58627c6ec97fca27
Author: Florian Dold <address@hidden>
AuthorDate: Thu Aug 22 23:36:36 2019 +0200

    support code for NFC tunneling
---
 src/android/index.ts    | 118 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/headless/helpers.ts |  13 +++++-
 src/wallet.ts           |  38 ++++++----------
 3 files changed, 140 insertions(+), 29 deletions(-)

diff --git a/src/android/index.ts b/src/android/index.ts
index 6d072a83..7ff9b21d 100644
--- a/src/android/index.ts
+++ b/src/android/index.ts
@@ -18,9 +18,103 @@
  * Imports.
  */
 import { Wallet } from "../wallet";
-import { getDefaultNodeWallet, withdrawTestBalance, DefaultNodeWalletArgs } 
from "../headless/helpers";
-import { openPromise } from "../promiseUtils";
+import {
+  getDefaultNodeWallet,
+  withdrawTestBalance,
+  DefaultNodeWalletArgs,
+  NodeHttpLib,
+} from "../headless/helpers";
+import { openPromise, OpenedPromise } from "../promiseUtils";
 import fs = require("fs");
+import axios from "axios";
+import { HttpRequestLibrary, HttpResponse } from "../http";
+import querystring = require("querystring");
+
+export class AndroidHttpLib implements HttpRequestLibrary {
+  useNfcTunnel: boolean = false;
+
+  private nodeHttpLib: HttpRequestLibrary = new NodeHttpLib();
+
+  private requestId = 1;
+
+  private requestMap: { [id: number]: OpenedPromise<HttpResponse> } = {};
+
+  constructor(private sendMessage: (m: string) => void) {}
+
+  get(url: string): Promise<HttpResponse> {
+    if (this.useNfcTunnel) {
+      const myId = this.requestId++;
+      const p = openPromise<HttpResponse>();
+      this.requestMap[myId] = p;
+      const request = {
+        method: "get",
+        url,
+      };
+      this.sendMessage(
+        JSON.stringify({
+          type: "tunnelHttp",
+          request,
+          id: myId,
+        }),
+      );
+      return p.promise;
+    } else {
+      return this.nodeHttpLib.get(url);
+    }
+  }
+
+  postJson(url: string, body: any): Promise<import("../http").HttpResponse> {
+    if (this.useNfcTunnel) {
+      const myId = this.requestId++;
+      const p = openPromise<HttpResponse>();
+      this.requestMap[myId] = p;
+      const request = {
+        method: "postJson",
+        url,
+        body,
+      };
+      this.sendMessage(
+        JSON.stringify({ type: "tunnelHttp", request, id: myId }),
+      );
+      return p.promise;
+    } else {
+      return this.nodeHttpLib.postJson(url, body);
+    }
+  }
+
+  postForm(url: string, form: any): Promise<import("../http").HttpResponse> {
+    if (this.useNfcTunnel) {
+      const myId = this.requestId++;
+      const p = openPromise<HttpResponse>();
+      this.requestMap[myId] = p;
+      const request = {
+        method: "postForm",
+        url,
+        form,
+      };
+      this.sendMessage(
+        JSON.stringify({ type: "tunnelHttp", request, id: myId }),
+      );
+      return p.promise;
+    } else {
+      return this.nodeHttpLib.postForm(url, form);
+    }
+  }
+
+  handleTunnelResponse(msg: any) {
+    const myId = msg.id;
+    const p = this.requestMap[myId];
+    if (!p) {
+      console.error(`no matching request for tunneled HTTP response, 
id=${myId}`);
+    }
+    if (msg.status == 200) {
+      p.resolve({ responseJson: msg.responseJson, status: msg.status });
+    } else {
+      p.reject(new Error(`unexpected HTTP status code ${msg.status}`));
+    }
+    delete this.requestMap[myId];
+  }
+}
 
 export function installAndroidWalletListener() {
   // @ts-ignore
@@ -33,6 +127,7 @@ export function installAndroidWalletListener() {
   }
   let maybeWallet: Wallet | undefined;
   let wp = openPromise<Wallet>();
+  let httpLib = new AndroidHttpLib(sendMessage);
   let walletArgs: DefaultNodeWalletArgs | undefined;
   const onMessage = async (msgStr: any) => {
     if (typeof msgStr !== "string") {
@@ -55,7 +150,8 @@ export function installAndroidWalletListener() {
           notifyHandler: async () => {
             sendMessage(JSON.stringify({ type: "notification" }));
           },
-          persistentStoragePath: msg.args.persistentStoragePath, 
+          persistentStoragePath: msg.args.persistentStoragePath,
+          httpLib: httpLib,
         };
         maybeWallet = await getDefaultNodeWallet(walletArgs);
         wp.resolve(maybeWallet);
@@ -82,13 +178,25 @@ export function installAndroidWalletListener() {
         result = await wallet.confirmPay(msg.args.proposalId, undefined);
         break;
       }
+      case "startTunnel": {
+        httpLib.useNfcTunnel = true;
+        break;
+      }
+      case "stopTunnel": {
+        httpLib.useNfcTunnel = false;
+        break;
+      }
+      case "tunnelResponse": {
+        httpLib.handleTunnelResponse(msg.args);
+        break;
+      }
       case "reset": {
         const wallet = await wp.promise;
-        wallet.stop()
+        wallet.stop();
         wp = openPromise<Wallet>();
         if (walletArgs && walletArgs.persistentStoragePath) {
           try {
-            fs.unlinkSync(walletArgs.persistentStoragePath)
+            fs.unlinkSync(walletArgs.persistentStoragePath);
           } catch (e) {
             console.error("Error while deleting the wallet db:", e);
           }
diff --git a/src/headless/helpers.ts b/src/headless/helpers.ts
index 7c4fa877..9652c630 100644
--- a/src/headless/helpers.ts
+++ b/src/headless/helpers.ts
@@ -120,6 +120,12 @@ export interface DefaultNodeWalletArgs {
    * Handler for asynchronous notifications from the wallet.
    */
   notifyHandler?: (reason: string) => void;
+
+  /**
+   * If specified, use this as HTTP request library instead
+   * of the default one.
+   */
+  httpLib?: HttpRequestLibrary;
 }
 
 /**
@@ -169,7 +175,12 @@ export async function getDefaultNodeWallet(
   const myBridgeIdbFactory = new BridgeIDBFactory(myBackend);
   const myIdbFactory: IDBFactory = (myBridgeIdbFactory as any) as IDBFactory;
 
-  const myHttpLib = new NodeHttpLib();
+  let myHttpLib;
+  if (args.httpLib) {
+    myHttpLib = args.httpLib;
+  } else {
+    myHttpLib = new NodeHttpLib();
+  }
 
   const myVersionChange = () => {
     console.error("version change requested, should not happen");
diff --git a/src/wallet.ts b/src/wallet.ts
index 50f3ee7e..b50f415d 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -45,8 +45,6 @@ import * as Amounts from "./amounts";
 
 import URI = require("urijs");
 
-import axios from "axios";
-
 import {
   CoinRecord,
   CoinStatus,
@@ -107,6 +105,7 @@ import {
   PreparePayResult,
 } from "./walletTypes";
 import { openPromise } from "./promiseUtils";
+import Axios from "axios";
 
 interface SpeculativePayData {
   payCoinInfo: PayCoinInfo;
@@ -787,13 +786,13 @@ export class Wallet {
     console.log("downloading contract from '" + urlWithNonce + "'");
     let resp;
     try {
-      resp = await axios.get(urlWithNonce, { validateStatus: s => s === 200 });
+      resp = await this.http.get(urlWithNonce);
     } catch (e) {
       console.log("contract download failed", e);
       throw e;
     }
 
-    const proposal = Proposal.checked(resp.data);
+    const proposal = Proposal.checked(resp.responseJson);
 
     const contractTermsHash = await this.hashContract(proposal.contract_terms);
 
@@ -853,18 +852,13 @@ export class Wallet {
     const payReq = { ...purchase.payReq, session_id: sessionId };
 
     try {
-      const config = {
-        headers: { "Content-Type": "application/json;charset=UTF-8" },
-        timeout: 5000 /* 5 seconds */,
-        validateStatus: (s: number) => s === 200,
-      };
-      resp = await axios.post(purchase.contractTerms.pay_url, payReq, config);
+      resp = await this.http.postJson(purchase.contractTerms.pay_url, payReq)
     } catch (e) {
       // Gives the user the option to retry / abort and refresh
       console.log("payment failed", e);
       throw e;
     }
-    const merchantResp = resp.data;
+    const merchantResp = resp.responseJson;
     console.log("got success from pay_url");
 
     const merchantPub = purchase.contractTerms.merchant_pub;
@@ -2541,6 +2535,10 @@ export class Wallet {
 
     // FIXME: do pagination instead of generating the full history
 
+    // We uniquely identify history rows via their timestamp.
+    // This works as timestamps are guaranteed to be monotonically
+    // increasing even 
+
     const proposals = await this.q()
       .iter<ProposalDownloadRecord>(Stores.proposals)
       .toArray();
@@ -3041,16 +3039,13 @@ export class Wallet {
     console.log("processing refund");
     let resp;
     try {
-      const config = {
-        validateStatus: (s: number) => s === 200,
-      };
-      resp = await axios.get(refundUrl, config);
+      resp = await this.http.get(refundUrl);
     } catch (e) {
       console.log("error downloading refund permission", e);
       throw e;
     }
 
-    const refundResponse = MerchantRefundResponse.checked(resp.data);
+    const refundResponse = MerchantRefundResponse.checked(resp.responseJson);
     return this.acceptRefundResponse(refundResponse);
   }
 
@@ -3260,17 +3255,14 @@ export class Wallet {
     }));
 
     try {
-      const config = {
-        validateStatus: (s: number) => s === 200,
-      };
       const req = { planchets: planchetsDetail, tip_id: tipToken.tip_id };
-      merchantResp = await axios.post(tipToken.pickup_url, req, config);
+      merchantResp = await this.http.postJson(tipToken.pickup_url, req);
     } catch (e) {
       console.log("tipping failed", e);
       throw e;
     }
 
-    const response = TipResponse.checked(merchantResp.data);
+    const response = TipResponse.checked(merchantResp.responseJson);
 
     if (response.reserve_sigs.length !== tipRecord.planchets.length) {
       throw Error("number of tip responses does not match requested 
planchets");
@@ -3389,14 +3381,14 @@ export class Wallet {
         timeout: 5000 /* 5 seconds */,
         validateStatus: (s: number) => s === 200,
       };
-      resp = await axios.post(purchase.contractTerms.pay_url, abortReq, 
config);
+      resp = await this.http.postJson(purchase.contractTerms.pay_url, 
abortReq);
     } catch (e) {
       // Gives the user the option to retry / abort and refresh
       console.log("aborting payment failed", e);
       throw e;
     }
 
-    const refundResponse = MerchantRefundResponse.checked(resp.data);
+    const refundResponse = MerchantRefundResponse.checked(resp.responseJson);
     await this.acceptRefundResponse(refundResponse);
 
     const markAbortDone = (p: PurchaseRecord) => {

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



reply via email to

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