gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: wallet-core: use new /kyc-che


From: gnunet
Subject: [taler-wallet-core] branch master updated: wallet-core: use new /kyc-check/H_PAYTO API, fix test
Date: Tue, 03 Sep 2024 21:15:28 +0200

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

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

The following commit(s) were added to refs/heads/master by this push:
     new a9b1e425b wallet-core: use new /kyc-check/H_PAYTO API, fix test
a9b1e425b is described below

commit a9b1e425bba7023740ec2883f18fb9e636f48759
Author: Florian Dold <florian@dold.me>
AuthorDate: Tue Sep 3 21:15:18 2024 +0200

    wallet-core: use new /kyc-check/H_PAYTO API, fix test
---
 .../src/integrationtests/test-kyc-peer-pull.ts     | 42 ++++++-------
 packages/taler-util/src/payto.ts                   | 29 +++++++++
 packages/taler-util/src/types-taler-common.ts      | 18 +-----
 packages/taler-util/src/types-taler-exchange.ts    |  4 +-
 packages/taler-wallet-core/src/db.ts               | 20 ++-----
 packages/taler-wallet-core/src/deposits.ts         | 17 +++---
 packages/taler-wallet-core/src/exchanges.ts        | 17 ++++--
 .../taler-wallet-core/src/pay-peer-pull-credit.ts  | 69 +++++++++++----------
 .../taler-wallet-core/src/pay-peer-push-credit.ts  | 64 +++++++++++---------
 packages/taler-wallet-core/src/withdraw.ts         | 70 +++++++++-------------
 10 files changed, 177 insertions(+), 173 deletions(-)

diff --git a/packages/taler-harness/src/integrationtests/test-kyc-peer-pull.ts 
b/packages/taler-harness/src/integrationtests/test-kyc-peer-pull.ts
index c6de961ab..cc5787f26 100644
--- a/packages/taler-harness/src/integrationtests/test-kyc-peer-pull.ts
+++ b/packages/taler-harness/src/integrationtests/test-kyc-peer-pull.ts
@@ -252,25 +252,6 @@ export async function runKycPeerPullTest(t: 
GlobalTestState) {
     summary: "test123",
   });
 
-  const prepRes = await w0.walletClient.call(
-    WalletApiOperation.PreparePeerPullDebit,
-    {
-      talerUri: pullRes.talerUri,
-    },
-  );
-
-  await w0.walletClient.call(WalletApiOperation.ConfirmPeerPullDebit, {
-    transactionId: prepRes.transactionId,
-  });
-
-  await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
-    transactionId: pullRes.transactionId as TransactionIdStr,
-    txState: {
-      major: TransactionMajorState.Pending,
-      minor: TransactionMinorState.MergeKycRequired,
-    },
-  });
-
   const txDet = await walletClient.call(WalletApiOperation.GetTransactionById, 
{
     transactionId: pullRes.transactionId,
   });
@@ -288,6 +269,25 @@ export async function runKycPeerPullTest(t: 
GlobalTestState) {
     paytoHash: kycPaytoHash,
   });
 
+  await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+    transactionId: pullRes.transactionId as TransactionIdStr,
+    txState: {
+      major: TransactionMajorState.Pending,
+      minor: TransactionMinorState.Ready,
+    },
+  });
+
+  const prepRes = await w0.walletClient.call(
+    WalletApiOperation.PreparePeerPullDebit,
+    {
+      talerUri: pullRes.talerUri,
+    },
+  );
+
+  await w0.walletClient.call(WalletApiOperation.ConfirmPeerPullDebit, {
+    transactionId: prepRes.transactionId,
+  });
+
   await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
     transactionId: pullRes.transactionId as TransactionIdStr,
     txState: {
@@ -297,7 +297,7 @@ export async function runKycPeerPullTest(t: 
GlobalTestState) {
 }
 
 /**
- * Initiate a pull debit transaction, wait until the transaction
+ * Initiate a pull credit transaction, wait until the transaction
  * is ready.
  */
 async function doPeerPullCredit(
@@ -332,7 +332,7 @@ async function doPeerPullCredit(
     transactionId: initRet.transactionId,
     txState: {
       major: TransactionMajorState.Pending,
-      minor: TransactionMinorState.Ready,
+      minor: TransactionMinorState.MergeKycRequired,
     },
   });
 
diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts
index f50f97e58..76b5ff0cf 100644
--- a/packages/taler-util/src/payto.ts
+++ b/packages/taler-util/src/payto.ts
@@ -218,6 +218,35 @@ export function hashPaytoUri(p: PaytoUri | string): 
Uint8Array {
   return hashTruncate32(stringToBytes(paytoUri + "\0"));
 }
 
+export function stringifyReservePaytoUri(
+  exchangeBaseUrl: string,
+  reservePub: string,
+): string {
+  const url = new URL(exchangeBaseUrl);
+  let target: string;
+  let domainWithOptPort: string;
+  if (url.protocol === "https:") {
+    target = "taler-reserve";
+    if (url.port != "443" && url.port !== "") {
+      domainWithOptPort = `${url.hostname}:${url.port}`;
+    } else {
+      domainWithOptPort = `${url.hostname}`;
+    }
+  } else {
+    target = "taler-reserve-http";
+    if (url.port != "80" && url.port !== "") {
+      domainWithOptPort = `${url.hostname}:${url.port}`;
+    } else {
+      domainWithOptPort = `${url.hostname}`;
+    }
+  }
+  let optPath = "";
+  if (url.pathname !== "/" && url.pathname !== "") {
+    optPath = url.pathname;
+  }
+  return `payto://${target}/${domainWithOptPort}${optPath}/${reservePub}`;
+}
+
 /**
  * Parse a valid payto:// uri into a PaytoUri object
  * RFC 8905
diff --git a/packages/taler-util/src/types-taler-common.ts 
b/packages/taler-util/src/types-taler-common.ts
index 1db365ea7..dd983cf2e 100644
--- a/packages/taler-util/src/types-taler-common.ts
+++ b/packages/taler-util/src/types-taler-common.ts
@@ -40,7 +40,7 @@ import {
   codecForString,
   codecOptional,
 } from "./codec.js";
-import { codecForEither, ReservePub } from "./index.js";
+import { ReservePub, codecForEither } from "./index.js";
 import {
   TalerProtocolDuration,
   TalerProtocolTimestamp,
@@ -291,21 +291,6 @@ export type HashCodeString = string;
 
 export type WireSalt = string;
 
-export interface WalletKycUuid {
-  // UUID that the wallet should use when initiating
-  // the KYC check.
-  requirement_row: number;
-
-  // Hash of the payto:// account URI for the wallet.
-  h_payto: string;
-}
-
-export const codecForWalletKycUuid = (): Codec<WalletKycUuid> =>
-  buildCodecForObject<WalletKycUuid>()
-    .property("requirement_row", codecForNumber())
-    .property("h_payto", codecForString())
-    .build("WalletKycUuid");
-
 export interface MerchantUsingTemplateDetails {
   summary?: string;
   amount?: AmountString;
@@ -545,7 +530,6 @@ export interface ReserveAccount {
   signingKey: SigningKey;
 }
 
-
 export type PaginationParams = {
   /**
    * row identifier as the starting point of the query
diff --git a/packages/taler-util/src/types-taler-exchange.ts 
b/packages/taler-util/src/types-taler-exchange.ts
index 19f573f4b..bc8165991 100644
--- a/packages/taler-util/src/types-taler-exchange.ts
+++ b/packages/taler-util/src/types-taler-exchange.ts
@@ -1616,7 +1616,7 @@ export interface LegitimizationNeededResponse {
   // transaction was blocked and how to lift it. The account holder
   // should use the number to check for the account's AML/KYC status
   // using the /kyc-check/$REQUIREMENT_ROW endpoint.
-  requirement_row: Integer;
+  requirement_row: Integer | undefined;
 }
 
 export interface AccountKycStatus {
@@ -2422,7 +2422,7 @@ export const codecForLegitimizationNeededResponse =
       .property("hint", codecOptional(codecForString()))
       .property("h_payto", codecForString())
       .property("account_pub", codecOptional(codecForString()))
-      .property("requirement_row", codecForNumber())
+      .property("requirement_row", codecOptional(codecForNumber()))
       .build("TalerExchangeApi.LegitimizationNeededResponse");
 
 export const codecForAccountKycStatus = (): Codec<AccountKycStatus> =>
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index c48a43f11..21ec3f033 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -1466,11 +1466,6 @@ export type WgInfo =
 
 export type KycUserType = "individual" | "business";
 
-export interface KycPendingInfo {
-  paytoHash: string;
-  requirementRow: number;
-}
-
 /**
  * Group of withdrawal operations that need to be executed.
  * (Either for a normal withdrawal or from a reward.)
@@ -1486,9 +1481,7 @@ export interface WithdrawalGroupRecord {
 
   wgInfo: WgInfo;
 
-  kycPending?: KycPendingInfo;
-
-  kycUrl?: string;
+  kycPaytoHash?: string;
 
   kycAccessToken?: string;
 
@@ -1838,8 +1831,7 @@ export interface DepositGroupRecord {
 }
 
 export interface DepositKycInfo {
-  kycUrl: string;
-  requirementRow: number;
+  accessToken: string;
   paytoHash: string;
   exchangeBaseUrl: string;
 }
@@ -2029,9 +2021,7 @@ export interface PeerPullCreditRecord {
    */
   status: PeerPullPaymentCreditStatus;
 
-  kycInfo?: KycPendingInfo;
-
-  kycUrl?: string;
+  kycPaytoHash?: string;
 
   kycAccessToken?: string;
 
@@ -2109,9 +2099,7 @@ export interface PeerPushPaymentIncomingRecord {
    */
   currency: string | undefined;
 
-  kycInfo?: KycPendingInfo;
-
-  kycUrl?: string;
+  kycPaytoHash?: string;
 
   kycAccessToken?: string;
 }
diff --git a/packages/taler-wallet-core/src/deposits.ts 
b/packages/taler-wallet-core/src/deposits.ts
index e4b378f44..34b19df80 100644
--- a/packages/taler-wallet-core/src/deposits.ts
+++ b/packages/taler-wallet-core/src/deposits.ts
@@ -88,9 +88,9 @@ import {
   DepositElementStatus,
   DepositGroupRecord,
   DepositInfoPerExchange,
+  DepositKycInfo,
   DepositOperationStatus,
   DepositTrackingInfo,
-  KycPendingInfo,
   RefreshOperationStatus,
   WalletDbAllStoresReadOnlyTransaction,
   WalletDbReadWriteTransaction,
@@ -779,7 +779,7 @@ async function processDepositGroupPendingKyc(
   }
 
   const url = new URL(
-    `kyc-check/${kycInfo.requirementRow}`,
+    `kyc-check/${kycInfo.paytoHash}`,
     kycInfo.exchangeBaseUrl,
   );
 
@@ -839,14 +839,14 @@ async function processDepositGroupPendingKyc(
 async function transitionToKycRequired(
   wex: WalletExecutionContext,
   depositGroup: DepositGroupRecord,
-  kycInfo: KycPendingInfo,
+  kycInfo: DepositKycInfo,
   exchangeUrl: string,
 ): Promise<TaskRunResult> {
   const { depositGroupId } = depositGroup;
 
   const ctx = new DepositTransactionContext(wex, depositGroupId);
 
-  const url = new URL(`kyc-check/${kycInfo.requirementRow}`, exchangeUrl);
+  const url = new URL(`kyc-check/${kycInfo.paytoHash}`, exchangeUrl);
   logger.info(`kyc url ${url.href}`);
   const kycStatusReq = await wex.http.fetch(url.href, {
     method: "GET",
@@ -870,9 +870,8 @@ async function transitionToKycRequired(
         const oldTxState = computeDepositTransactionStatus(dg);
         dg.kycInfo = {
           exchangeBaseUrl: exchangeUrl,
-          kycUrl: kycStatus.kyc_url,
           paytoHash: kycInfo.paytoHash,
-          requirementRow: kycInfo.requirementRow,
+          accessToken: null as any, // FIXME!
         };
         await tx.depositGroups.put(dg);
         await ctx.updateTransactionMeta(tx);
@@ -938,10 +937,10 @@ async function processDepositGroupPendingTrack(
           const paytoHash = encodeCrock(
             hashTruncate32(stringToBytes(depositGroup.wire.payto_uri + "\0")),
           );
-          const { requirement_row: requirementRow } = track;
-          const kycInfo: KycPendingInfo = {
+          const kycInfo: DepositKycInfo = {
             paytoHash,
-            requirementRow,
+            exchangeBaseUrl: exchangeBaseUrl,
+            accessToken: null as any, // FIXME!
           };
           return transitionToKycRequired(
             wex,
diff --git a/packages/taler-wallet-core/src/exchanges.ts 
b/packages/taler-wallet-core/src/exchanges.ts
index fe78c63aa..2c0386d0c 100644
--- a/packages/taler-wallet-core/src/exchanges.ts
+++ b/packages/taler-wallet-core/src/exchanges.ts
@@ -101,10 +101,12 @@ import {
   encodeCrock,
   getRandomBytes,
   hashDenomPub,
+  hashPaytoUri,
   j2s,
   makeErrorDetail,
   makeTalerErrorDetail,
   parsePaytoUri,
+  stringifyReservePaytoUri,
 } from "@gnu-taler/taler-util";
 import {
   HttpRequestLibrary,
@@ -3370,8 +3372,7 @@ async function handleExchangeKycRespLegi(
     accountPriv: reserve.reservePriv,
     accountPub: reserve.reservePub,
   });
-  const requirementRow = kycBody.requirement_row;
-  const reqUrl = new URL(`kyc-check/${requirementRow}`, exchangeBaseUrl);
+  const reqUrl = new URL(`kyc-check/${kycBody.h_payto}`, exchangeBaseUrl);
   const resp = await wex.http.fetch(reqUrl.href, {
     method: "GET",
     headers: {
@@ -3466,13 +3467,19 @@ async function handleExchangeKycPendingLegitimization(
     accountPriv: reserve.reservePriv,
     accountPub: reserve.reservePub,
   });
-  const requirementRow = reserve.requirementRow;
-  checkDbInvariant(!!requirementRow, "requirement row");
+
+  const reservePayto = stringifyReservePaytoUri(
+    exchange.baseUrl,
+    reserve.reservePub,
+  );
+
+  const paytoHash = encodeCrock(hashPaytoUri(reservePayto));
+
   const resp = await wex.ws.runLongpollQueueing(
     wex,
     exchange.baseUrl,
     async (timeoutMs) => {
-      const reqUrl = new URL(`kyc-check/${requirementRow}`, exchange.baseUrl);
+      const reqUrl = new URL(`kyc-check/${paytoHash}`, exchange.baseUrl);
       reqUrl.searchParams.set("timeout_ms", `${timeoutMs}`);
       logger.info(`long-polling wallet KYC status at ${reqUrl.href}`);
       return await wex.http.fetch(reqUrl.href, {
diff --git a/packages/taler-wallet-core/src/pay-peer-pull-credit.ts 
b/packages/taler-wallet-core/src/pay-peer-pull-credit.ts
index 45ca93a40..7c69fbaa9 100644
--- a/packages/taler-wallet-core/src/pay-peer-pull-credit.ts
+++ b/packages/taler-wallet-core/src/pay-peer-pull-credit.ts
@@ -43,11 +43,11 @@ import {
   TransactionState,
   TransactionType,
   WalletAccountMergeFlags,
-  WalletKycUuid,
   assertUnreachable,
   checkDbInvariant,
+  codecForAccountKycStatus,
   codecForAny,
-  codecForWalletKycUuid,
+  codecForLegitimizationNeededResponse,
   encodeCrock,
   getRandomBytes,
   j2s,
@@ -55,7 +55,10 @@ import {
   stringifyTalerUri,
   talerPaytoFromExchangeReserve,
 } from "@gnu-taler/taler-util";
-import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
+import {
+  readResponseJsonOrThrow,
+  readSuccessResponseJsonOrThrow,
+} from "@gnu-taler/taler-util/http";
 import {
   PendingTaskType,
   TaskIdStr,
@@ -71,7 +74,6 @@ import {
   runWithClientCancellation,
 } from "./common.js";
 import {
-  KycPendingInfo,
   OperationRetryRecord,
   PeerPullCreditRecord,
   PeerPullPaymentCreditStatus,
@@ -262,6 +264,14 @@ export class PeerPullCreditTransactionContext implements 
TransactionContext {
       TaskIdentifiers.forPeerPullPaymentInitiation(pullCredit);
     let pullCreditOrt = await tx.operationRetries.get(pullCreditOpId);
 
+    let kycUrl: string | undefined = undefined;
+    if (pullCredit.kycPaytoHash) {
+      kycUrl = new URL(
+        `kyc-spa/${pullCredit.kycPaytoHash}`,
+        pullCredit.exchangeBaseUrl,
+      ).href;
+    }
+
     if (wsr) {
       if (wsr.wgInfo.withdrawalType !== WithdrawalRecordType.PeerPullCredit) {
         throw Error(`Unexpected withdrawalType: ${wsr.wgInfo.withdrawalType}`);
@@ -308,7 +318,8 @@ export class PeerPullCreditTransactionContext implements 
TransactionContext {
           tag: TransactionType.PeerPullCredit,
           pursePub: pullCredit.pursePub,
         }),
-        kycUrl: pullCredit.kycUrl,
+        // FIXME: Is this the KYC URL of the withdrawal group?!
+        kycUrl: kycUrl,
         ...(wsrOrt?.lastError
           ? {
               error: silentWithdrawalErrorForInvoice
@@ -343,7 +354,9 @@ export class PeerPullCreditTransactionContext implements 
TransactionContext {
         tag: TransactionType.PeerPullCredit,
         pursePub: pullCredit.pursePub,
       }),
-      kycUrl: pullCredit.kycUrl,
+      kycUrl,
+      kycAccessToken: pullCredit.kycAccessToken,
+      kycPaytoHash: pullCredit.kycPaytoHash,
       ...(pullCreditOrt?.lastError ? { error: pullCreditOrt.lastError } : {}),
     };
   }
@@ -758,7 +771,7 @@ async function longpollKycStatus(
   wex: WalletExecutionContext,
   pursePub: string,
   exchangeUrl: string,
-  kycInfo: KycPendingInfo,
+  kycPaytoHash: string,
 ): Promise<TaskRunResult> {
   // FIXME: What if this changes? Should be part of the p2p record
   const mergeReserveInfo = await getMergeReserveInfo(wex, {
@@ -771,7 +784,7 @@ async function longpollKycStatus(
   });
 
   const ctx = new PeerPullCreditTransactionContext(wex, pursePub);
-  const url = new URL(`kyc-check/${kycInfo.requirementRow}`, exchangeUrl);
+  const url = new URL(`kyc-check/${kycPaytoHash}`, exchangeUrl);
   const kycStatusRes = await wex.ws.runLongpollQueueing(
     wex,
     url.hostname,
@@ -1049,9 +1062,9 @@ async function handlePeerPullCreditCreatePurse(
 
   if (httpResp.status === HttpStatusCode.UnavailableForLegalReasons) {
     const respJson = await httpResp.json();
-    const kycPending = codecForWalletKycUuid().decode(respJson);
+    const kycPending = codecForLegitimizationNeededResponse().decode(respJson);
     logger.info(`kyc uuid response: ${j2s(kycPending)}`);
-    return processPeerPullCreditKycRequired(wex, pullIni, kycPending);
+    return processPeerPullCreditKycRequired(wex, pullIni, kycPending.h_payto);
   }
 
   const resp = await readSuccessResponseJsonOrThrow(httpResp, codecForAny());
@@ -1111,14 +1124,14 @@ export async function processPeerPullCredit(
     case PeerPullPaymentCreditStatus.PendingReady:
       return queryPurseForPeerPullCredit(wex, pullIni);
     case PeerPullPaymentCreditStatus.PendingMergeKycRequired: {
-      if (!pullIni.kycInfo) {
-        throw Error("invalid state, kycInfo required");
+      if (!pullIni.kycPaytoHash) {
+        throw Error("invalid state, kycPaytoHash required");
       }
       return await longpollKycStatus(
         wex,
         pursePub,
         pullIni.exchangeBaseUrl,
-        pullIni.kycInfo,
+        pullIni.kycPaytoHash,
       );
     }
     case PeerPullPaymentCreditStatus.PendingCreatePurse:
@@ -1217,13 +1230,7 @@ async function processPeerPullCreditBalanceKyc(
         return TransitionResult.stay();
       }
       rec.status = PeerPullPaymentCreditStatus.PendingBalanceKycRequired;
-      delete rec.kycInfo;
       rec.kycAccessToken = ret.walletKycAccessToken;
-      // FIXME: #9109 this should not be constructed here, it should be an 
opaque URL from exchange response
-      rec.kycUrl = new URL(
-        `kyc-spa/${ret.walletKycAccessToken}`,
-        exchangeBaseUrl,
-      ).href;
       return TransitionResult.transition(rec);
     });
     return TaskRunResult.progress();
@@ -1235,7 +1242,7 @@ async function processPeerPullCreditBalanceKyc(
 async function processPeerPullCreditKycRequired(
   wex: WalletExecutionContext,
   peerIni: PeerPullCreditRecord,
-  kycPending: WalletKycUuid,
+  kycPayoHash: string,
 ): Promise<TaskRunResult> {
   const ctx = new PeerPullCreditTransactionContext(wex, peerIni.pursePub);
   const { pursePub } = peerIni;
@@ -1250,10 +1257,7 @@ async function processPeerPullCreditKycRequired(
     accountPub: mergeReserveInfo.reservePub,
   });
 
-  const url = new URL(
-    `kyc-check/${kycPending.requirement_row}`,
-    peerIni.exchangeBaseUrl,
-  );
+  const url = new URL(`kyc-check/${kycPayoHash}`, peerIni.exchangeBaseUrl);
 
   logger.info(`kyc url ${url.href}`);
   const kycStatusRes = await wex.http.fetch(url.href, {
@@ -1271,7 +1275,10 @@ async function processPeerPullCreditKycRequired(
     logger.warn("kyc requested, but already fulfilled");
     return TaskRunResult.backoff();
   } else if (kycStatusRes.status === HttpStatusCode.Accepted) {
-    const kycStatus = await kycStatusRes.json();
+    const kycStatus = await readResponseJsonOrThrow(
+      kycStatusRes,
+      codecForAccountKycStatus(),
+    );
     logger.info(`kyc status: ${j2s(kycStatus)}`);
     const { transitionInfo, result } = await wex.db.runReadWriteTx(
       { storeNames: ["peerPullCredit", "transactionsMeta"] },
@@ -1284,11 +1291,11 @@ async function processPeerPullCreditKycRequired(
           };
         }
         const oldTxState = computePeerPullCreditTransactionState(peerInc);
-        peerInc.kycInfo = {
-          paytoHash: kycPending.h_payto,
-          requirementRow: kycPending.requirement_row,
-        };
-        peerInc.kycUrl = kycStatus.kyc_url;
+        peerInc.kycPaytoHash = kycPayoHash;
+        logger.info(
+          `setting peer-pull-credit kyc payto hash to ${kycPayoHash}`,
+        );
+        peerInc.kycAccessToken = kycStatus.access_token;
         peerInc.status = PeerPullPaymentCreditStatus.PendingMergeKycRequired;
         const newTxState = computePeerPullCreditTransactionState(peerInc);
         await tx.peerPullCredit.put(peerInc);
@@ -1300,7 +1307,7 @@ async function processPeerPullCreditKycRequired(
       },
     );
     notifyTransition(wex, ctx.transactionId, transitionInfo);
-    return TaskRunResult.backoff();
+    return result;
   } else {
     throw Error(`unexpected response from kyc-check (${kycStatusRes.status})`);
   }
diff --git a/packages/taler-wallet-core/src/pay-peer-push-credit.ts 
b/packages/taler-wallet-core/src/pay-peer-push-credit.ts
index 7c131c45a..d18f8712d 100644
--- a/packages/taler-wallet-core/src/pay-peer-push-credit.ts
+++ b/packages/taler-wallet-core/src/pay-peer-push-credit.ts
@@ -23,6 +23,7 @@ import {
   ExchangePurseMergeRequest,
   ExchangeWalletKycStatus,
   HttpStatusCode,
+  LegitimizationNeededResponse,
   Logger,
   NotificationType,
   PeerContractTerms,
@@ -37,13 +38,13 @@ import {
   TransactionState,
   TransactionType,
   WalletAccountMergeFlags,
-  WalletKycUuid,
   assertUnreachable,
   checkDbInvariant,
+  codecForAccountKycStatus,
   codecForAny,
   codecForExchangeGetContractResponse,
+  codecForLegitimizationNeededResponse,
   codecForPeerContractTerms,
-  codecForWalletKycUuid,
   decodeCrock,
   eddsaGetPublic,
   encodeCrock,
@@ -52,7 +53,10 @@ import {
   parsePayPushUri,
   talerPaytoFromExchangeReserve,
 } from "@gnu-taler/taler-util";
-import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
+import {
+  readResponseJsonOrThrow,
+  readSuccessResponseJsonOrThrow,
+} from "@gnu-taler/taler-util/http";
 import {
   PendingTaskType,
   TaskIdStr,
@@ -67,7 +71,6 @@ import {
   requireExchangeTosAcceptedOrThrow,
 } from "./common.js";
 import {
-  KycPendingInfo,
   OperationRetryRecord,
   PeerPushCreditStatus,
   PeerPushPaymentIncomingRecord,
@@ -263,6 +266,11 @@ export class PeerPushCreditTransactionContext implements 
TransactionContext {
 
     const peerContractTerms = ct.contractTermsRaw;
 
+    let kycUrl: string | undefined = undefined;
+    if (wg?.kycAccessToken && wg.exchangeBaseUrl) {
+      kycUrl = new URL(`kyc-spa/${wg.kycAccessToken}`, 
wg.exchangeBaseUrl).href;
+    }
+
     if (wg) {
       if (wg.wgInfo.withdrawalType !== WithdrawalRecordType.PeerPushCredit) {
         throw Error("invalid withdrawal group type for push payment credit");
@@ -291,8 +299,8 @@ export class PeerPushCreditTransactionContext implements 
TransactionContext {
           tag: TransactionType.PeerPushCredit,
           peerPushCreditId: pushInc.peerPushCreditId,
         }),
-        kycUrl: wg.kycUrl,
-        kycPaytoHash: wg.kycPending?.paytoHash,
+        kycUrl,
+        kycPaytoHash: wg.kycPaytoHash,
         ...(wgRetryRecord?.lastError ? { error: wgRetryRecord.lastError } : 
{}),
       };
     }
@@ -313,8 +321,8 @@ export class PeerPushCreditTransactionContext implements 
TransactionContext {
         expiration: peerContractTerms.purse_expiration,
         summary: peerContractTerms.summary,
       },
-      kycUrl: pushInc.kycUrl,
-      kycPaytoHash: pushInc.kycInfo?.paytoHash,
+      kycUrl,
+      kycPaytoHash: pushInc.kycPaytoHash,
       timestamp: timestampPreciseFromDb(pushInc.timestamp),
       transactionId: constructTransactionIdentifier({
         tag: TransactionType.PeerPushCredit,
@@ -750,7 +758,7 @@ async function longpollKycStatus(
   wex: WalletExecutionContext,
   peerPushCreditId: string,
   exchangeUrl: string,
-  kycInfo: KycPendingInfo,
+  kycPaytoHash: string,
 ): Promise<TaskRunResult> {
   const ctx = new PeerPushCreditTransactionContext(wex, peerPushCreditId);
 
@@ -764,7 +772,7 @@ async function longpollKycStatus(
     accountPub: mergeReserveInfo.reservePub,
   });
 
-  const url = new URL(`kyc-check/${kycInfo.requirementRow}`, exchangeUrl);
+  const url = new URL(`kyc-check/${kycPaytoHash}`, exchangeUrl);
   logger.info(`kyc url ${url.href}`);
   const kycStatusRes = await wex.ws.runLongpollQueueing(
     wex,
@@ -816,7 +824,7 @@ async function longpollKycStatus(
 async function processPeerPushCreditKycRequired(
   wex: WalletExecutionContext,
   peerInc: PeerPushPaymentIncomingRecord,
-  kycPending: WalletKycUuid,
+  kycPending: LegitimizationNeededResponse,
 ): Promise<TaskRunResult> {
   const transactionId = constructTransactionIdentifier({
     tag: TransactionType.PeerPushCredit,
@@ -839,7 +847,7 @@ async function processPeerPushCreditKycRequired(
   });
 
   const url = new URL(
-    `kyc-check/${kycPending.requirement_row}`,
+    `kyc-check/${kycPending.h_payto}`,
     peerInc.exchangeBaseUrl,
   );
 
@@ -863,6 +871,10 @@ async function processPeerPushCreditKycRequired(
   } else if (kycStatusRes.status === HttpStatusCode.Accepted) {
     const kycStatus = await kycStatusRes.json();
     logger.info(`kyc status: ${j2s(kycStatus)}`);
+    const statusResp = await readResponseJsonOrThrow(
+      kycStatusRes,
+      codecForAccountKycStatus(),
+    );
     const { transitionInfo, result } = await wex.db.runReadWriteTx(
       { storeNames: ["peerPushCredit", "transactionsMeta"] },
       async (tx) => {
@@ -874,11 +886,8 @@ async function processPeerPushCreditKycRequired(
           };
         }
         const oldTxState = computePeerPushCreditTransactionState(peerInc);
-        peerInc.kycInfo = {
-          paytoHash: kycPending.h_payto,
-          requirementRow: kycPending.requirement_row,
-        };
-        peerInc.kycUrl = kycStatus.kyc_url;
+        peerInc.kycPaytoHash = kycPending.h_payto;
+        peerInc.kycAccessToken = statusResp.access_token;
         peerInc.status = PeerPushCreditStatus.PendingMergeKycRequired;
         const newTxState = computePeerPushCreditTransactionState(peerInc);
         await tx.peerPushCredit.put(peerInc);
@@ -979,9 +988,12 @@ async function handlePendingMerge(
 
   if (mergeHttpResp.status === HttpStatusCode.UnavailableForLegalReasons) {
     const respJson = await mergeHttpResp.json();
-    const kycPending = codecForWalletKycUuid().decode(respJson);
-    logger.info(`kyc uuid response: ${j2s(kycPending)}`);
-    return processPeerPushCreditKycRequired(wex, peerInc, kycPending);
+    const kycLegiNeededResp =
+      codecForLegitimizationNeededResponse().decode(respJson);
+    logger.info(
+      `kyc legitimization needed response: ${j2s(kycLegiNeededResp)}`,
+    );
+    return processPeerPushCreditKycRequired(wex, peerInc, kycLegiNeededResp);
   }
 
   logger.trace(`merge request: ${j2s(mergeReq)}`);
@@ -1163,14 +1175,14 @@ export async function processPeerPushCredit(
 
   switch (peerInc.status) {
     case PeerPushCreditStatus.PendingMergeKycRequired: {
-      if (!peerInc.kycInfo) {
-        throw Error("invalid state, kycInfo required");
+      if (!peerInc.kycPaytoHash) {
+        throw Error("invalid state, kycPaytoHash required");
       }
       return await longpollKycStatus(
         wex,
         peerPushCreditId,
         peerInc.exchangeBaseUrl,
-        peerInc.kycInfo,
+        peerInc.kycPaytoHash,
       );
     }
     case PeerPushCreditStatus.PendingMerge: {
@@ -1255,13 +1267,7 @@ async function processPeerPushCreditBalanceKyc(
         return TransitionResult.stay();
       }
       rec.status = PeerPushCreditStatus.PendingBalanceKycRequired;
-      delete rec.kycInfo;
       rec.kycAccessToken = ret.walletKycAccessToken;
-      // FIXME: #9109 this should not be constructed here, it should be an 
opaque URL from exchange response
-      rec.kycUrl = new URL(
-        `kyc-spa/${ret.walletKycAccessToken}`,
-        exchangeBaseUrl,
-      ).href;
       return TransitionResult.transition(rec);
     });
     return TaskRunResult.progress();
diff --git a/packages/taler-wallet-core/src/withdraw.ts 
b/packages/taler-wallet-core/src/withdraw.ts
index b0c27bd8a..0d47e08c7 100644
--- a/packages/taler-wallet-core/src/withdraw.ts
+++ b/packages/taler-wallet-core/src/withdraw.ts
@@ -93,8 +93,8 @@ import {
   codecForCashinConversionResponse,
   codecForConversionBankConfig,
   codecForExchangeWithdrawBatchResponse,
+  codecForLegitimizationNeededResponse,
   codecForReserveStatus,
-  codecForWalletKycUuid,
   codecForWithdrawOperationStatusResponse,
   encodeCrock,
   getErrorDetailFromException,
@@ -135,7 +135,6 @@ import {
   CoinSourceType,
   DenominationRecord,
   DenominationVerificationStatus,
-  KycPendingInfo,
   OperationRetryRecord,
   PlanchetRecord,
   PlanchetStatus,
@@ -241,9 +240,9 @@ function buildTransactionForBankIntegratedWithdraw(
         wg.status === WithdrawalGroupStatus.Done ||
         wg.status === WithdrawalGroupStatus.PendingReady,
     },
-    kycUrl: wg.kycUrl,
+    kycUrl: kycDetails?.kycUrl,
     kycAccessToken: wg.kycAccessToken,
-    kycPaytoHash: wg.kycPending?.paytoHash,
+    kycPaytoHash: wg.kycPaytoHash,
     timestamp: timestampPreciseFromDb(wg.timestampStart),
     transactionId: constructTransactionIdentifier({
       tag: TransactionType.Withdrawal,
@@ -302,7 +301,7 @@ function buildTransactionForManualWithdraw(
         wg.status === WithdrawalGroupStatus.PendingReady,
       reserveClosingDelay: exchangeDetails?.reserveClosingDelay ?? { d_us: 0 },
     },
-    kycUrl: wg.kycUrl,
+    kycUrl: kycDetails?.kycUrl,
     exchangeBaseUrl: wg.exchangeBaseUrl,
     timestamp: timestampPreciseFromDb(wg.timestampStart),
     transactionId: constructTransactionIdentifier({
@@ -365,13 +364,20 @@ export class WithdrawTransactionContext implements 
TransactionContext {
 
     let kycDetails: TxKycDetails | undefined = undefined;
 
+    if (!exchangeBaseUrl) {
+      return undefined;
+    }
+
     switch (withdrawalGroupRecord.status) {
       case WithdrawalGroupStatus.PendingKyc:
       case WithdrawalGroupStatus.SuspendedKyc: {
         kycDetails = {
           kycAccessToken: withdrawalGroupRecord.kycAccessToken,
-          kycPaytoHash: withdrawalGroupRecord.kycPending?.paytoHash,
-          kycUrl: withdrawalGroupRecord.kycUrl,
+          kycPaytoHash: withdrawalGroupRecord.kycPaytoHash,
+          kycUrl: new URL(
+            `kyc-spa/${withdrawalGroupRecord.kycAccessToken}`,
+            exchangeBaseUrl,
+          ).href,
         };
         break;
       }
@@ -1027,13 +1033,8 @@ async function processWithdrawalGroupBalanceKyc(
         return TransitionResult.stay();
       }
       wg.status = WithdrawalGroupStatus.PendingBalanceKyc;
-      wg.kycPending = undefined;
       wg.kycAccessToken = ret.walletKycAccessToken;
-      // FIXME: #9109 this should not be constructed here, it should be an 
opaque URL from exchange response
-      wg.kycUrl = new URL(
-        `kyc-spa/${ret.walletKycAccessToken}`,
-        exchangeBaseUrl,
-      ).href;
+      delete wg.kycPaytoHash;
       return TransitionResult.transition(wg);
     });
     return TaskRunResult.progress();
@@ -1152,7 +1153,9 @@ export async function getBankWithdrawalInfo(
     if (resp.detail) {
       throw TalerError.fromUncheckedDetail(resp.detail);
     } else {
-      throw TalerError.fromException(new Error("failed to get bank remote 
config"))
+      throw TalerError.fromException(
+        new Error("failed to get bank remote config"),
+      );
     }
   }
   const { body: status } = resp;
@@ -1347,13 +1350,6 @@ interface WithdrawalBatchResult {
   batchResp: ExchangeWithdrawBatchResponse;
 }
 
-// FIXME: Move to exchange API types
-enum ExchangeAmlStatus {
-  Normal = 0,
-  Pending = 1,
-  Frozen = 2,
-}
-
 /**
  * Transition a transaction from pending(ready)
  * into a pending(kyc|aml) state, in case KYC is required.
@@ -1367,20 +1363,17 @@ async function handleKycRequired(
 ): Promise<void> {
   logger.info("withdrawal requires KYC");
   const respJson = await resp.json();
-  const uuidResp = codecForWalletKycUuid().decode(respJson);
+  const legiRequiredResp =
+    codecForLegitimizationNeededResponse().decode(respJson);
   const withdrawalGroupId = withdrawalGroup.withdrawalGroupId;
   const ctx = new WithdrawTransactionContext(wex, withdrawalGroupId);
-  logger.info(`kyc uuid response: ${j2s(uuidResp)}`);
+  logger.info(`kyc uuid response: ${j2s(legiRequiredResp)}`);
   const exchangeUrl = withdrawalGroup.exchangeBaseUrl;
-  const kycInfo: KycPendingInfo = {
-    paytoHash: uuidResp.h_payto,
-    requirementRow: uuidResp.requirement_row,
-  };
   const sigResp = await wex.cryptoApi.signWalletKycAuth({
     accountPriv: withdrawalGroup.reservePriv,
     accountPub: withdrawalGroup.reservePub,
   });
-  const url = new URL(`kyc-check/${kycInfo.requirementRow}`, exchangeUrl);
+  const url = new URL(`kyc-check/${legiRequiredResp.h_payto}`, exchangeUrl);
   logger.info(`kyc url ${url.href}`);
   // We do not longpoll here, as this is the initial request to get 
information about the KYC.
   const kycStatusRes = await wex.http.fetch(url.href, {
@@ -1434,16 +1427,7 @@ async function handleKycRequired(
       if (wg2.status !== WithdrawalGroupStatus.PendingReady) {
         return TransitionResult.stay();
       }
-      // FIXME: Why not just store the whole kycState?!
-      wg2.kycPending = {
-        paytoHash: uuidResp.h_payto,
-        requirementRow: uuidResp.requirement_row,
-      };
-      // FIXME: #9109 this should not be constructed here, it should be an 
opaque URL from exchange response
-      wg2.kycUrl = new URL(
-        `kyc-spa/${kycStatus.access_token}`,
-        exchangeUrl,
-      ).href;
+      wg2.kycPaytoHash = legiRequiredResp.h_payto;
       wg2.kycAccessToken = kycStatus.access_token;
       wg2.status = WithdrawalGroupStatus.PendingKyc;
       return TransitionResult.transition(wg2);
@@ -2019,12 +2003,12 @@ async function processWithdrawalGroupPendingKyc(
     wex,
     withdrawalGroup.withdrawalGroupId,
   );
-  const kycInfo = withdrawalGroup.kycPending;
-  if (!kycInfo) {
+  const kycPaytoHash = withdrawalGroup.kycPaytoHash;
+  if (!kycPaytoHash) {
     throw Error("no kyc info available in pending(kyc)");
   }
   const exchangeUrl = withdrawalGroup.exchangeBaseUrl;
-  const url = new URL(`kyc-check/${kycInfo.requirementRow}`, exchangeUrl);
+  const url = new URL(`kyc-check/${kycPaytoHash}`, exchangeUrl);
   const sigResp = await wex.cryptoApi.signWalletKycAuth({
     accountPriv: withdrawalGroup.reservePriv,
     accountPub: withdrawalGroup.reservePub,
@@ -2056,8 +2040,8 @@ async function processWithdrawalGroupPendingKyc(
       }
       switch (rec.status) {
         case WithdrawalGroupStatus.PendingKyc: {
-          delete rec.kycPending;
-          delete rec.kycUrl;
+          delete rec.kycAccessToken;
+          delete rec.kycAccessToken;
           rec.status = WithdrawalGroupStatus.PendingReady;
           return TransitionResult.transition(rec);
         }

-- 
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]