gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (99d7cbae0 -> 420493b3e)


From: gnunet
Subject: [taler-wallet-core] branch master updated (99d7cbae0 -> 420493b3e)
Date: Tue, 17 Jan 2023 20:01:37 +0100

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

sebasjm pushed a change to branch master
in repository wallet-core.

    from 99d7cbae0 -output nice message
     new 3cde52eff use URL api to stringify payto://
     new 5be2d128e payto URI builder
     new eeea3e62a stronger type check to be sure that ErrorDetails is 
consistent
     new 2c14a180c re-use the same kyc function from withdrawal for deposits
     new 252382a93 throw error after 5 seconds if wallet-core didn't reply to a 
command
     new 420493b3e use payto builder and prevent showing cancel for non-payment

The 6 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:
 packages/taler-util/src/payto.ts                   | 71 +++++++++++++++++--
 packages/taler-wallet-core/src/db.ts               |  5 +-
 packages/taler-wallet-core/src/errors.ts           | 66 ++++++++++++-----
 .../src/operations/backup/index.ts                 |  2 +-
 .../taler-wallet-core/src/operations/deposits.ts   | 40 +++++++----
 .../taler-wallet-core/src/operations/withdraw.ts   | 82 +++++++++++++---------
 packages/taler-wallet-core/src/util/http.ts        | 14 +++-
 .../src/browserHttpLib.ts                          | 12 ++--
 .../src/platform/chrome.ts                         | 54 ++++++++------
 .../src/serviceWorkerHttpLib.ts                    | 19 +++--
 .../src/wallet/DepositPage/state.ts                | 10 +--
 .../src/wallet/ManageAccount/state.ts              |  2 +-
 .../src/wallet/ManageAccount/views.tsx             | 22 +++---
 .../src/wallet/Transaction.tsx                     | 38 +++++-----
 14 files changed, 298 insertions(+), 139 deletions(-)

diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts
index 8eb0b88a8..dd35b44be 100644
--- a/packages/taler-util/src/payto.ts
+++ b/packages/taler-util/src/payto.ts
@@ -55,6 +55,66 @@ export interface PaytoUriBitcoin extends PaytoUriGeneric {
 
 const paytoPfx = "payto://";
 
+export function buildPayto(
+  type: "iban",
+  iban: string,
+  bic: string | undefined,
+): PaytoUriIBAN;
+export function buildPayto(
+  type: "bitcoin",
+  address: string,
+  reserve: string | undefined,
+): PaytoUriBitcoin;
+export function buildPayto(
+  type: "x-taler-bank",
+  host: string,
+  account: string,
+): PaytoUriTalerBank;
+export function buildPayto(
+  type: "iban" | "bitcoin" | "x-taler-bank",
+  first: string,
+  second?: string,
+): PaytoUriGeneric {
+  switch (type) {
+    case "bitcoin": {
+      const result: PaytoUriBitcoin = {
+        isKnown: true,
+        targetType: "bitcoin",
+        targetPath: first,
+        params: {},
+        segwitAddrs: !second ? [] : generateFakeSegwitAddress(second, first),
+      };
+      return result;
+    }
+    case "iban": {
+      const result: PaytoUriIBAN = {
+        isKnown: true,
+        targetType: "iban",
+        iban: first,
+        params: {},
+        targetPath: !second ? first : `${second}/${first}`,
+      };
+      return result;
+    }
+    case "x-taler-bank": {
+      if (!second) throw Error("missing account for payto://x-taler-bank");
+      const result: PaytoUriTalerBank = {
+        isKnown: true,
+        targetType: "x-taler-bank",
+        host: first,
+        account: second,
+        params: {},
+        targetPath: `${first}/${second}`,
+      };
+      return result;
+    }
+    default: {
+      const unknownType: never = type;
+      throw Error(`unknown payto:// type ${unknownType}`);
+    }
+  }
+}
+
 /**
  * Add query parameters to a payto URI
  */
@@ -81,13 +141,12 @@ export function addPaytoQueryParams(
  * @returns
  */
 export function stringifyPaytoUri(p: PaytoUri): string {
-  const url = `${paytoPfx}${p.targetType}/${p.targetPath}`;
+  const url = new URL(`${paytoPfx}${p.targetType}/${p.targetPath}`);
   const paramList = !p.params ? [] : Object.entries(p.params);
-  if (paramList.length > 0) {
-    const search = paramList.map(([key, value]) => 
`${key}=${value}`).join("&");
-    return `${url}?${search}`;
-  }
-  return url;
+  paramList.forEach(([key, value]) => {
+    url.searchParams.set(key, value);
+  });
+  return url.href;
 }
 
 /**
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index e6131334c..d2d01e100 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -1361,7 +1361,8 @@ export type WgInfo =
   | WgInfoBankPeerPush
   | WgInfoBankRecoup;
 
-export interface WithdrawalKycPendingInfo {
+export type KycUserType = "individual" | "business";
+export interface KycPendingInfo {
   paytoHash: string;
   requirementRow: number;
 }
@@ -1380,7 +1381,7 @@ export interface WithdrawalGroupRecord {
 
   wgInfo: WgInfo;
 
-  kycPending?: WithdrawalKycPendingInfo;
+  kycPending?: KycPendingInfo;
 
   /**
    * Secret seed used to derive planchets.
diff --git a/packages/taler-wallet-core/src/errors.ts 
b/packages/taler-wallet-core/src/errors.ts
index 7dbba2e2e..038bdbc7c 100644
--- a/packages/taler-wallet-core/src/errors.ts
+++ b/packages/taler-wallet-core/src/errors.ts
@@ -32,6 +32,8 @@ import {
   TransactionType,
 } from "@gnu-taler/taler-util";
 
+type empty = Record<string, never>;
+
 export interface DetailsMap {
   [TalerErrorCode.WALLET_PENDING_OPERATION_FAILED]: {
     innerError: TalerErrorDetail;
@@ -44,13 +46,13 @@ export interface DetailsMap {
     exchangeProtocolVersion: string;
     walletProtocolVersion: string;
   };
-  [TalerErrorCode.WALLET_WITHDRAWAL_OPERATION_ABORTED_BY_BANK]: {};
-  [TalerErrorCode.WALLET_TIPPING_COIN_SIGNATURE_INVALID]: {};
+  [TalerErrorCode.WALLET_WITHDRAWAL_OPERATION_ABORTED_BY_BANK]: empty;
+  [TalerErrorCode.WALLET_TIPPING_COIN_SIGNATURE_INVALID]: empty;
   [TalerErrorCode.WALLET_ORDER_ALREADY_CLAIMED]: {
     orderId: string;
     claimUrl: string;
   };
-  [TalerErrorCode.WALLET_CONTRACT_TERMS_MALFORMED]: {};
+  [TalerErrorCode.WALLET_CONTRACT_TERMS_MALFORMED]: empty;
   [TalerErrorCode.WALLET_CONTRACT_TERMS_SIGNATURE_INVALID]: {
     merchantPub: string;
     orderId: string;
@@ -62,18 +64,46 @@ export interface DetailsMap {
   [TalerErrorCode.WALLET_INVALID_TALER_PAY_URI]: {
     talerPayUri: string;
   };
-  [TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR]: {};
-  [TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION]: {};
-  [TalerErrorCode.WALLET_BANK_INTEGRATION_PROTOCOL_VERSION_INCOMPATIBLE]: {};
-  [TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN]: {};
-  [TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED]: {};
-  [TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT]: {};
-  [TalerErrorCode.WALLET_NETWORK_ERROR]: {};
-  [TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE]: {};
-  [TalerErrorCode.WALLET_EXCHANGE_COIN_SIGNATURE_INVALID]: {};
-  [TalerErrorCode.WALLET_WITHDRAWAL_GROUP_INCOMPLETE]: {};
-  [TalerErrorCode.WALLET_CORE_NOT_AVAILABLE]: {};
-  [TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR]: {};
+  [TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR]: {
+    requestUrl: string;
+    requestMethod: string;
+    httpStatusCode: number;
+    errorResponse?: any;
+  };
+  [TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION]: {
+    stack?: string;
+  };
+  [TalerErrorCode.WALLET_BANK_INTEGRATION_PROTOCOL_VERSION_INCOMPATIBLE]: {
+    exchangeProtocolVersion: string;
+    walletProtocolVersion: string;
+  };
+  [TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN]: {
+    operation: string;
+  };
+  [TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED]: {
+    requestUrl: string;
+    requestMethod: string;
+    throttleStats: Record<string, unknown>;
+  };
+  [TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT]: empty;
+  [TalerErrorCode.WALLET_NETWORK_ERROR]: {
+    requestUrl: string;
+    requestMethod: string;
+  };
+  [TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE]: {
+    requestUrl: string;
+    requestMethod: string;
+    httpStatusCode: number;
+    validationError?: string;
+  };
+  [TalerErrorCode.WALLET_EXCHANGE_COIN_SIGNATURE_INVALID]: empty;
+  [TalerErrorCode.WALLET_WITHDRAWAL_GROUP_INCOMPLETE]: {
+    errorsPerCoin: Record<number, TalerErrorDetail>;
+  };
+  [TalerErrorCode.WALLET_CORE_NOT_AVAILABLE]: empty;
+  [TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR]: {
+    httpStatusCode: number;
+  };
   [TalerErrorCode.WALLET_PAY_MERCHANT_SERVER_ERROR]: {
     requestError: TalerErrorDetail;
   };
@@ -84,7 +114,7 @@ export interface DetailsMap {
     detail: string;
   };
   [TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED]: {
-    // FIXME!
+    kycUrl: string;
   };
   [TalerErrorCode.WALLET_DEPOSIT_GROUP_INSUFFICIENT_BALANCE]: {
     insufficientBalanceDetails: PayMerchantInsufficientBalanceDetails;
@@ -94,7 +124,7 @@ export interface DetailsMap {
   };
 }
 
-type ErrBody<Y> = Y extends keyof DetailsMap ? DetailsMap[Y] : never;
+type ErrBody<Y> = Y extends keyof DetailsMap ? DetailsMap[Y] : empty;
 
 export function makeErrorDetail<C extends TalerErrorCode>(
   code: C,
@@ -133,7 +163,7 @@ function getDefaultHint(code: number): string {
   }
 }
 
-export class TalerProtocolViolationError<T = any> extends Error {
+export class TalerProtocolViolationError extends Error {
   constructor(hint?: string) {
     let msg: string;
     if (hint) {
diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts 
b/packages/taler-wallet-core/src/operations/backup/index.ts
index 27d27da0d..7d3953ebb 100644
--- a/packages/taler-wallet-core/src/operations/backup/index.ts
+++ b/packages/taler-wallet-core/src/operations/backup/index.ts
@@ -734,7 +734,7 @@ async function runFirstBackupCycleForProvider(
     case OperationAttemptResultType.Error:
       throw TalerError.fromDetail(
         TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION,
-        resp.errorDetail,
+        resp.errorDetail as any, //FIXME create an error for backup problems
       );
     case OperationAttemptResultType.Finished:
       return {
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index b529e5ead..71caae5b3 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -21,6 +21,7 @@ import {
   AbsoluteTime,
   AmountJson,
   Amounts,
+  bytesToString,
   CancellationToken,
   canonicalJson,
   codecForDepositSuccess,
@@ -35,6 +36,7 @@ import {
   ExchangeDepositRequest,
   GetFeeForDepositRequest,
   getRandomBytes,
+  hashTruncate32,
   hashWire,
   HttpStatusCode,
   Logger,
@@ -44,6 +46,7 @@ import {
   PrepareDepositRequest,
   PrepareDepositResponse,
   RefreshReason,
+  stringToBytes,
   TalerErrorCode,
   TalerProtocolTimestamp,
   TrackDepositGroupRequest,
@@ -59,6 +62,7 @@ import {
   TransactionStatus,
 } from "../db.js";
 import { TalerError } from "../errors.js";
+import { checkKycStatus } from "../index.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import { readSuccessResponseJsonOrThrow } from "../util/http.js";
 import { OperationAttemptResult } from "../util/retries.js";
@@ -151,7 +155,28 @@ export async function processDepositGroup(
 
     if (depositGroup.transactionPerCoin[i] !== TransactionStatus.Wired) {
       const track = await trackDepositPermission(ws, depositGroup, perm);
-      updatedTxStatus = txStatusFromTrack(track);
+
+      if (track.type === "accepted") {
+        if (!track.kyc_ok && track.requirement_row !== undefined) {
+          updatedTxStatus = TransactionStatus.KycRequired;
+          const { requirement_row: requirementRow } = track;
+          const paytoHash = encodeCrock(
+            hashTruncate32(stringToBytes(depositGroup.wire.payto_uri + "\0")),
+          );
+          await checkKycStatus(
+            ws,
+            perm.exchange_url,
+            { paytoHash, requirementRow },
+            "individual",
+          );
+        } else {
+          updatedTxStatus = TransactionStatus.Accepted;
+        }
+      } else if (track.type === "wired") {
+        updatedTxStatus = TransactionStatus.Wired;
+      } else {
+        updatedTxStatus = TransactionStatus.Unknown;
+      }
     }
 
     if (updatedTxStatus !== undefined || updatedDeposit !== undefined) {
@@ -199,19 +224,6 @@ export async function processDepositGroup(
   return OperationAttemptResult.finishedEmpty();
 }
 
-function txStatusFromTrack(t: TrackTransaction): TransactionStatus {
-  if (t.type === "accepted") {
-    if (!t.kyc_ok && t.requirement_row !== undefined) {
-      return TransactionStatus.KycRequired;
-    }
-    return TransactionStatus.Accepted;
-  }
-  if (t.type === "wired") {
-    return TransactionStatus.Wired;
-  }
-  return TransactionStatus.Unknown;
-}
-
 export async function trackDepositGroup(
   ws: InternalWalletState,
   req: TrackDepositGroupRequest,
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts 
b/packages/taler-wallet-core/src/operations/withdraw.ts
index a1a39bf32..c1cc94413 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -26,7 +26,6 @@ import {
   AmountJson,
   AmountLike,
   Amounts,
-  AmountString,
   BankWithdrawDetails,
   CancellationToken,
   canonicalizeBaseUrl,
@@ -70,13 +69,14 @@ import {
   CoinSourceType,
   DenominationRecord,
   DenominationVerificationStatus,
+  KycPendingInfo,
+  KycUserType,
   PlanchetRecord,
   PlanchetStatus,
   WalletStoresV1,
   WgInfo,
   WithdrawalGroupRecord,
   WithdrawalGroupStatus,
-  WithdrawalKycPendingInfo,
   WithdrawalRecordType,
 } from "../db.js";
 import {
@@ -86,7 +86,6 @@ import {
 } from "../errors.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import {
-  getExchangeTosStatus,
   makeCoinAvailable,
   makeExchangeListItem,
   runOperationWithErrorReporting,
@@ -927,7 +926,7 @@ async function queryReserve(
   );
   reserveUrl.searchParams.set("timeout_ms", "30000");
 
-  logger.info(`querying reserve status via ${reserveUrl}`);
+  logger.info(`querying reserve status via ${reserveUrl.href}`);
 
   const resp = await ws.http.get(reserveUrl.href, {
     timeout: getReserveRequestTimeout(withdrawalGroup),
@@ -1165,9 +1164,9 @@ export async function processWithdrawalGroup(
   let numFinished = 0;
   let numKycRequired = 0;
   let finishedForFirstTime = false;
-  let errorsPerCoin: Record<number, TalerErrorDetail> = {};
+  const errorsPerCoin: Record<number, TalerErrorDetail> = {};
 
-  let res = await ws.db
+  const res = await ws.db
     .mktx((x) => [x.coins, x.withdrawalGroups, x.planchets])
     .runReadWrite(async (tx) => {
       const wg = await tx.withdrawalGroups.get(withdrawalGroupId);
@@ -1210,39 +1209,22 @@ export async function processWithdrawalGroup(
 
   if (numKycRequired > 0) {
     if (kycInfo) {
-      const url = new URL(
-        `kyc-check/${kycInfo.requirementRow}/${kycInfo.paytoHash}/individual`,
+      await checkKycStatus(
+        ws,
         withdrawalGroup.exchangeBaseUrl,
+        kycInfo,
+        "individual",
       );
-      logger.info(`kyc url ${url.href}`);
-      const kycStatusReq = await ws.http.fetch(url.href, {
-        method: "GET",
-      });
-      logger.warn("kyc requested, but already fulfilled");
-      if (kycStatusReq.status === HttpStatusCode.Ok) {
-        return {
-          type: OperationAttemptResultType.Pending,
-          result: undefined,
-        };
-      } else if (kycStatusReq.status === HttpStatusCode.Accepted) {
-        const kycStatus = await kycStatusReq.json();
-        logger.info(`kyc status: ${j2s(kycStatus)}`);
-        throw TalerError.fromDetail(
-          TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED,
-          {
-            kycUrl: kycStatus.kyc_url,
-          },
-          `KYC check required for withdrawal`,
-        );
-      } else {
-        throw Error(
-          `unexpected response from kyc-check (${kycStatusReq.status})`,
-        );
-      }
+      return {
+        type: OperationAttemptResultType.Pending,
+        result: undefined,
+      };
     } else {
       throw TalerError.fromDetail(
         TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED,
-        {},
+        {
+          //FIXME we can't rise KYC error here since we don't have the url
+        } as any,
         `KYC check required for withdrawal (not yet implemented in 
wallet-core)`,
       );
     }
@@ -1270,6 +1252,38 @@ export async function processWithdrawalGroup(
   };
 }
 
+export async function checkKycStatus(
+  ws: InternalWalletState,
+  exchangeUrl: string,
+  kycInfo: KycPendingInfo,
+  userType: KycUserType,
+): Promise<void> {
+  const url = new URL(
+    `kyc-check/${kycInfo.requirementRow}/${kycInfo.paytoHash}/${userType}`,
+    exchangeUrl,
+  );
+  logger.info(`kyc url ${url.href}`);
+  const kycStatusReq = await ws.http.fetch(url.href, {
+    method: "GET",
+  });
+  logger.warn("kyc requested, but already fulfilled");
+  if (kycStatusReq.status === HttpStatusCode.Ok) {
+    return;
+  } else if (kycStatusReq.status === HttpStatusCode.Accepted) {
+    const kycStatus = await kycStatusReq.json();
+    logger.info(`kyc status: ${j2s(kycStatus)}`);
+    throw TalerError.fromDetail(
+      TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED,
+      {
+        kycUrl: kycStatus.kyc_url,
+      },
+      `KYC check required for withdrawal`,
+    );
+  } else {
+    throw Error(`unexpected response from kyc-check (${kycStatusReq.status})`);
+  }
+}
+
 const AGE_MASK_GROUPS = "8:10:12:14:16:18"
   .split(":")
   .map((n) => parseInt(n, 10));
diff --git a/packages/taler-wallet-core/src/util/http.ts 
b/packages/taler-wallet-core/src/util/http.ts
index 118da40fe..1da31a315 100644
--- a/packages/taler-wallet-core/src/util/http.ts
+++ b/packages/taler-wallet-core/src/util/http.ts
@@ -68,7 +68,7 @@ export interface HttpRequestOptions {
    */
   cancellationToken?: CancellationToken;
 
-  body?: string | ArrayBuffer | Object;
+  body?: string | ArrayBuffer | Record<string, unknown>;
 }
 
 /**
@@ -185,6 +185,7 @@ export async function readUnexpectedResponseDetails(
     TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR,
     {
       requestUrl: httpResponse.requestUrl,
+      requestMethod: httpResponse.requestMethod,
       httpStatusCode: httpResponse.status,
       errorResponse: errJson,
     },
@@ -211,6 +212,7 @@ export async function readSuccessResponseJsonOrErrorCode<T>(
       TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
       {
         requestUrl: httpResponse.requestUrl,
+        requestMethod: httpResponse.requestMethod,
         httpStatusCode: httpResponse.status,
         validationError: e.toString(),
       },
@@ -223,11 +225,18 @@ export async function 
readSuccessResponseJsonOrErrorCode<T>(
   };
 }
 
+type HttpErrorDetails = {
+  requestUrl: string;
+  requestMethod: string;
+  httpStatusCode: number;
+};
+
 export function getHttpResponseErrorDetails(
   httpResponse: HttpResponse,
-): Record<string, unknown> {
+): HttpErrorDetails {
   return {
     requestUrl: httpResponse.requestUrl,
+    requestMethod: httpResponse.requestMethod,
     httpStatusCode: httpResponse.status,
   };
 }
@@ -240,6 +249,7 @@ export function throwUnexpectedRequestError(
     TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR,
     {
       requestUrl: httpResponse.requestUrl,
+      requestMethod: httpResponse.requestMethod,
       httpStatusCode: httpResponse.status,
       errorResponse: talerErrorResponse,
     },
diff --git a/packages/taler-wallet-webextension/src/browserHttpLib.ts 
b/packages/taler-wallet-webextension/src/browserHttpLib.ts
index 26fa8eb11..165a0037c 100644
--- a/packages/taler-wallet-webextension/src/browserHttpLib.ts
+++ b/packages/taler-wallet-webextension/src/browserHttpLib.ts
@@ -90,7 +90,8 @@ export class BrowserHttpLib implements HttpRequestLibrary {
           TalerError.fromDetail(
             TalerErrorCode.WALLET_NETWORK_ERROR,
             {
-              requestUrl: requestUrl,
+              requestUrl,
+              requestMethod,
             },
             "Could not make request",
           ),
@@ -103,7 +104,8 @@ export class BrowserHttpLib implements HttpRequestLibrary {
             const exc = TalerError.fromDetail(
               TalerErrorCode.WALLET_NETWORK_ERROR,
               {
-                requestUrl: requestUrl,
+                requestUrl,
+                requestMethod,
               },
               "HTTP request failed (status 0, maybe URI scheme was wrong?)",
             );
@@ -124,7 +126,8 @@ export class BrowserHttpLib implements HttpRequestLibrary {
               throw TalerError.fromDetail(
                 TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
                 {
-                  requestUrl: requestUrl,
+                  requestUrl,
+                  requestMethod,
                   httpStatusCode: myRequest.status,
                 },
                 "Invalid JSON from HTTP response",
@@ -134,7 +137,8 @@ export class BrowserHttpLib implements HttpRequestLibrary {
               throw TalerError.fromDetail(
                 TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
                 {
-                  requestUrl: requestUrl,
+                  requestUrl,
+                  requestMethod,
                   httpStatusCode: myRequest.status,
                 },
                 "Invalid JSON from HTTP response",
diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts 
b/packages/taler-wallet-webextension/src/platform/chrome.ts
index fc51a65fb..23730c2d3 100644
--- a/packages/taler-wallet-webextension/src/platform/chrome.ts
+++ b/packages/taler-wallet-webextension/src/platform/chrome.ts
@@ -14,8 +14,13 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { classifyTalerUri, Logger, TalerUriType } from "@gnu-taler/taler-util";
-import { WalletOperations } from "@gnu-taler/taler-wallet-core";
+import {
+  classifyTalerUri,
+  Logger,
+  TalerErrorCode,
+  TalerUriType,
+} from "@gnu-taler/taler-util";
+import { TalerError, WalletOperations } from "@gnu-taler/taler-wallet-core";
 import { BackgroundOperations } from "../wxApi.js";
 import {
   BackgroundPlatformAPI,
@@ -321,12 +326,15 @@ async function sendMessageToBackground<
   return new Promise<any>((resolve, reject) => {
     logger.trace("send operation to the wallet background", message);
     let timedout = false;
-    setTimeout(() => {
+    const timerId = setTimeout(() => {
       timedout = true;
-      reject("timedout");
-    }, 2000);
+      throw TalerError.fromDetail(TalerErrorCode.GENERIC_TIMEOUT, {});
+    }, 5 * 1000); //five seconds
     chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => {
-      if (timedout) return false;
+      if (timedout) {
+        return false; //already rejected
+      }
+      clearTimeout(timerId);
       if (chrome.runtime.lastError) {
         reject(chrome.runtime.lastError.message);
       } else {
@@ -576,26 +584,26 @@ function setAlertedIcon(): void {
 
 interface OffscreenCanvasRenderingContext2D
   extends CanvasState,
-    CanvasTransform,
-    CanvasCompositing,
-    CanvasImageSmoothing,
-    CanvasFillStrokeStyles,
-    CanvasShadowStyles,
-    CanvasFilters,
-    CanvasRect,
-    CanvasDrawPath,
-    CanvasUserInterface,
-    CanvasText,
-    CanvasDrawImage,
-    CanvasImageData,
-    CanvasPathDrawingStyles,
-    CanvasTextDrawingStyles,
-    CanvasPath {
+  CanvasTransform,
+  CanvasCompositing,
+  CanvasImageSmoothing,
+  CanvasFillStrokeStyles,
+  CanvasShadowStyles,
+  CanvasFilters,
+  CanvasRect,
+  CanvasDrawPath,
+  CanvasUserInterface,
+  CanvasText,
+  CanvasDrawImage,
+  CanvasImageData,
+  CanvasPathDrawingStyles,
+  CanvasTextDrawingStyles,
+  CanvasPath {
   readonly canvas: OffscreenCanvas;
 }
 declare const OffscreenCanvasRenderingContext2D: {
   prototype: OffscreenCanvasRenderingContext2D;
-  new (): OffscreenCanvasRenderingContext2D;
+  new(): OffscreenCanvasRenderingContext2D;
 };
 
 interface OffscreenCanvas extends EventTarget {
@@ -608,7 +616,7 @@ interface OffscreenCanvas extends EventTarget {
 }
 declare const OffscreenCanvas: {
   prototype: OffscreenCanvas;
-  new (width: number, height: number): OffscreenCanvas;
+  new(width: number, height: number): OffscreenCanvas;
 };
 
 function createCanvas(size: number): OffscreenCanvas {
diff --git a/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts 
b/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts
index 82d11a15a..4b47e89d5 100644
--- a/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts
+++ b/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts
@@ -104,8 +104,8 @@ export class ServiceWorkerHttpLib implements 
HttpRequestLibrary {
         status: response.status,
         requestMethod,
         requestUrl,
-        json: makeJsonHandler(response, requestUrl),
-        text: makeTextHandler(response, requestUrl),
+        json: makeJsonHandler(response, requestUrl, requestMethod),
+        text: makeTextHandler(response, requestUrl, requestMethod),
         bytes: async () => (await response.blob()).arrayBuffer(),
       };
     } catch (e) {
@@ -145,7 +145,11 @@ export class ServiceWorkerHttpLib implements 
HttpRequestLibrary {
   }
 }
 
-function makeTextHandler(response: Response, requestUrl: string) {
+function makeTextHandler(
+  response: Response,
+  requestUrl: string,
+  requestMethod: string,
+) {
   return async function getJsonFromResponse(): Promise<any> {
     let respText;
     try {
@@ -155,6 +159,7 @@ function makeTextHandler(response: Response, requestUrl: 
string) {
         TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
         {
           requestUrl,
+          requestMethod,
           httpStatusCode: response.status,
         },
         "Invalid JSON from HTTP response",
@@ -164,7 +169,11 @@ function makeTextHandler(response: Response, requestUrl: 
string) {
   };
 }
 
-function makeJsonHandler(response: Response, requestUrl: string) {
+function makeJsonHandler(
+  response: Response,
+  requestUrl: string,
+  requestMethod: string,
+) {
   return async function getJsonFromResponse(): Promise<any> {
     let responseJson;
     try {
@@ -174,6 +183,7 @@ function makeJsonHandler(response: Response, requestUrl: 
string) {
         TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
         {
           requestUrl,
+          requestMethod,
           httpStatusCode: response.status,
         },
         "Invalid JSON from HTTP response",
@@ -184,6 +194,7 @@ function makeJsonHandler(response: Response, requestUrl: 
string) {
         TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
         {
           requestUrl,
+          requestMethod,
           httpStatusCode: response.status,
         },
         "Invalid JSON from HTTP response",
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts 
b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
index d7d9f2da7..b744b80e5 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
@@ -60,8 +60,8 @@ export function useComponentState({
     parsed !== undefined
       ? parsed
       : currency !== undefined
-        ? Amounts.zeroOfCurrency(currency)
-        : undefined;
+      ? Amounts.zeroOfCurrency(currency)
+      : undefined;
   // const [accountIdx, setAccountIdx] = useState<number>(0);
   const [selectedAccount, setSelectedAccount] = useState<PaytoUri>();
 
@@ -147,7 +147,7 @@ export function useComponentState({
       initialValue ?? ({} as any),
     );
     const amountStr = Amounts.stringify(amount);
-    const depositPaytoUri = 
`payto://${currentAccount.targetType}/${currentAccount.targetPath}`;
+    const depositPaytoUri = stringifyPaytoUri(currentAccount);
 
     // eslint-disable-next-line react-hooks/rules-of-hooks
     const hook = useAsyncAsHook(async () => {
@@ -193,8 +193,8 @@ export function useComponentState({
     const amountError = !isDirty
       ? undefined
       : Amounts.cmp(balance, amount) === -1
-        ? `Too much, your current balance is 
${Amounts.stringifyValue(balance)}`
-        : undefined;
+      ? `Too much, your current balance is ${Amounts.stringifyValue(balance)}`
+      : undefined;
 
     const unableToDeposit =
       Amounts.isZero(totalToDeposit) || //deposit may be zero because of fee
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ManageAccount/state.ts 
b/packages/taler-wallet-webextension/src/wallet/ManageAccount/state.ts
index f7383d483..50e71c144 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManageAccount/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ManageAccount/state.ts
@@ -128,7 +128,7 @@ export function useComponentState({
       }),
     },
     accountByType,
-    deleteAccount,
+    deleteAccount: pushAlertOnError(deleteAccount),
     onAccountAdded: {
       onClick: unableToAdd ? undefined : pushAlertOnError(addAccount),
     },
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx
index e5be8d17d..75e1feca4 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx
@@ -15,10 +15,12 @@
  */
 
 import {
+  buildPayto,
   KnownBankAccountsInfo,
   PaytoUriBitcoin,
   PaytoUriIBAN,
   PaytoUriTalerBank,
+  stringifyPaytoUri,
 } from "@gnu-taler/taler-util";
 import { styled } from "@linaria/react";
 import { Fragment, h, VNode } from "preact";
@@ -411,7 +413,8 @@ function BitcoinAddressAccount({ field }: { field: 
TextFieldHandler }): VNode {
         onChange={(v) => {
           setValue(v);
           if (!errors && field.onInput) {
-            field.onInput(`payto://bitcoin/${v}`);
+            const p = buildPayto("bitcoin", v, undefined);
+            field.onInput(stringifyPaytoUri(p));
           }
         }}
       />
@@ -448,8 +451,9 @@ function TalerBankAddressAccount({
         disabled={!field.onInput}
         onChange={(v) => {
           setHost(v);
-          if (!errors && field.onInput) {
-            field.onInput(`payto://x-taler-bank/${v}/${account}`);
+          if (!errors && field.onInput && account) {
+            const p = buildPayto("x-taler-bank", v, account);
+            field.onInput(stringifyPaytoUri(p));
           }
         }}
       />
@@ -462,8 +466,9 @@ function TalerBankAddressAccount({
         error={account !== undefined ? errors?.account : undefined}
         onChange={(v) => {
           setAccount(v || "");
-          if (!errors && field.onInput) {
-            field.onInput(`payto://x-taler-bank/${host}/${v}`);
+          if (!errors && field.onInput && host) {
+            const p = buildPayto("x-taler-bank", host, v);
+            field.onInput(stringifyPaytoUri(p));
           }
         }}
       />
@@ -500,10 +505,9 @@ function IbanAddressAccount({ field }: { field: 
TextFieldHandler }): VNode {
     name: string,
   ): void {
     if (!errors && field.onInput) {
-      const path = bic === undefined ? iban : `${bic}/${iban}`;
-      field.onInput(
-        `payto://iban/${path}?receiver-name=${encodeURIComponent(name)}`,
-      );
+      const p = buildPayto("iban", iban, bic);
+      p.params["receiver-name"] = name;
+      field.onInput(stringifyPaytoUri(p));
     }
   }
   return (
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx 
b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index 7c0682588..397972636 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -202,20 +202,24 @@ function TransactionTemplate({
   const SHOWING_RETRY_THRESHOLD_SECS = 30;
 
   const showSend = false;
-  // (transaction.type === TransactionType.PeerPullCredit ||
-  //   transaction.type === TransactionType.PeerPushDebit) &&
-  //   !transaction.info.completed;
-  const showRetry =
-    transaction.error !== undefined ||
-    transaction.timestamp.t_s === "never" ||
-    (transaction.extendedStatus === ExtendedStatus.Pending &&
-      differenceInSeconds(new Date(), transaction.timestamp.t_s * 1000) >
-        SHOWING_RETRY_THRESHOLD_SECS);
+  const hasCancelTransactionImplemented =
+    transaction.type === TransactionType.Payment;
 
   const transactionStillActive =
     transaction.extendedStatus !== ExtendedStatus.Aborted &&
     transaction.extendedStatus !== ExtendedStatus.Done &&
     transaction.extendedStatus !== ExtendedStatus.Failed;
+
+  // show retry if there is an error in an active state, or after some time
+  // if it is not aborting
+  const showRetry =
+    transactionStillActive &&
+    (transaction.error !== undefined ||
+      (transaction.extendedStatus !== ExtendedStatus.Aborting &&
+        (transaction.timestamp.t_s === "never" ||
+          differenceInSeconds(new Date(), transaction.timestamp.t_s * 1000) >
+            SHOWING_RETRY_THRESHOLD_SECS)));
+
   return (
     <Fragment>
       <section style={{ padding: 8, textAlign: "center" }}>
@@ -353,13 +357,15 @@ function TransactionTemplate({
             </Button>
           ) : null}
           {transactionStillActive ? (
-            <Button
-              variant="contained"
-              color="error"
-              onClick={doCheckBeforeCancel as SafeHandler<void>}
-            >
-              <i18n.Translate>Cancel</i18n.Translate>
-            </Button>
+            hasCancelTransactionImplemented ? (
+              <Button
+                variant="contained"
+                color="error"
+                onClick={doCheckBeforeCancel as SafeHandler<void>}
+              >
+                <i18n.Translate>Cancel</i18n.Translate>
+              </Button>
+            ) : undefined
           ) : (
             <Button
               variant="contained"

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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