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: attempt to imple


From: gnunet
Subject: [taler-wallet-core] branch master updated: wallet-core: attempt to implement KYC auth, test still failing
Date: Fri, 06 Sep 2024 16:30:58 +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 726df07be wallet-core: attempt to implement KYC auth, test still 
failing
726df07be is described below

commit 726df07be957dbc053ff633242ca3c4bd752e8fd
Author: Florian Dold <florian@dold.me>
AuthorDate: Fri Sep 6 16:30:55 2024 +0200

    wallet-core: attempt to implement KYC auth, test still failing
---
 .../test-kyc-balance-withdrawal.ts                 |   4 +-
 .../integrationtests/test-kyc-deposit-aggregate.ts |   4 +-
 .../integrationtests/test-kyc-deposit-deposit.ts   |   4 +-
 .../integrationtests/test-kyc-exchange-wallet.ts   |   4 +-
 .../integrationtests/test-kyc-form-withdrawal.ts   |   4 +-
 .../src/integrationtests/test-kyc-new-measure.ts   |   4 +-
 .../src/integrationtests/test-kyc-peer-pull.ts     |   4 +-
 .../src/integrationtests/test-kyc-peer-push.ts     |   4 +-
 .../test-kyc-threshold-withdrawal.ts               |   4 +-
 packages/taler-util/src/types-taler-exchange.ts    |   9 +
 .../src/types-taler-wallet-transactions.ts         |   1 +
 .../src/crypto/cryptoImplementation.ts             |  12 +-
 packages/taler-wallet-core/src/db.ts               |   3 +
 packages/taler-wallet-core/src/deposits.ts         | 328 ++++++++++++++++-----
 packages/taler-wallet-core/src/pay-merchant.ts     |   4 +-
 packages/taler-wallet-core/src/withdraw.ts         |   8 +-
 16 files changed, 299 insertions(+), 102 deletions(-)

diff --git 
a/packages/taler-harness/src/integrationtests/test-kyc-balance-withdrawal.ts 
b/packages/taler-harness/src/integrationtests/test-kyc-balance-withdrawal.ts
index 12e62607b..320db6912 100644
--- a/packages/taler-harness/src/integrationtests/test-kyc-balance-withdrawal.ts
+++ b/packages/taler-harness/src/integrationtests/test-kyc-balance-withdrawal.ts
@@ -29,7 +29,7 @@ import {
 } from "@gnu-taler/taler-util";
 import {
   createSyncCryptoApi,
-  EddsaKeypairStrings,
+  EddsaKeyPairStrings,
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
@@ -57,7 +57,7 @@ interface KycTestEnv {
   exchangeBankAccount: HarnessExchangeBankAccount;
   walletClient: WalletClient;
   walletService: WalletService;
-  amlKeypair: EddsaKeypairStrings;
+  amlKeypair: EddsaKeyPairStrings;
 }
 
 async function createKycTestkudosEnvironment(
diff --git 
a/packages/taler-harness/src/integrationtests/test-kyc-deposit-aggregate.ts 
b/packages/taler-harness/src/integrationtests/test-kyc-deposit-aggregate.ts
index 4dc072882..741025b83 100644
--- a/packages/taler-harness/src/integrationtests/test-kyc-deposit-aggregate.ts
+++ b/packages/taler-harness/src/integrationtests/test-kyc-deposit-aggregate.ts
@@ -24,7 +24,7 @@ import {
 } from "@gnu-taler/taler-util";
 import {
   createSyncCryptoApi,
-  EddsaKeypairStrings,
+  EddsaKeyPairStrings,
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
@@ -52,7 +52,7 @@ interface KycTestEnv {
   exchangeBankAccount: HarnessExchangeBankAccount;
   walletClient: WalletClient;
   walletService: WalletService;
-  amlKeypair: EddsaKeypairStrings;
+  amlKeypair: EddsaKeyPairStrings;
 }
 
 async function createKycTestkudosEnvironment(
diff --git 
a/packages/taler-harness/src/integrationtests/test-kyc-deposit-deposit.ts 
b/packages/taler-harness/src/integrationtests/test-kyc-deposit-deposit.ts
index 2ee58c7d8..08e5f1091 100644
--- a/packages/taler-harness/src/integrationtests/test-kyc-deposit-deposit.ts
+++ b/packages/taler-harness/src/integrationtests/test-kyc-deposit-deposit.ts
@@ -24,7 +24,7 @@ import {
 } from "@gnu-taler/taler-util";
 import {
   createSyncCryptoApi,
-  EddsaKeypairStrings,
+  EddsaKeyPairStrings,
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
@@ -52,7 +52,7 @@ interface KycTestEnv {
   exchangeBankAccount: HarnessExchangeBankAccount;
   walletClient: WalletClient;
   walletService: WalletService;
-  amlKeypair: EddsaKeypairStrings;
+  amlKeypair: EddsaKeyPairStrings;
 }
 
 async function createKycTestkudosEnvironment(
diff --git 
a/packages/taler-harness/src/integrationtests/test-kyc-exchange-wallet.ts 
b/packages/taler-harness/src/integrationtests/test-kyc-exchange-wallet.ts
index 5ff260a1d..da1ba6d8d 100644
--- a/packages/taler-harness/src/integrationtests/test-kyc-exchange-wallet.ts
+++ b/packages/taler-harness/src/integrationtests/test-kyc-exchange-wallet.ts
@@ -26,7 +26,7 @@ import {
 } from "@gnu-taler/taler-util";
 import {
   createSyncCryptoApi,
-  EddsaKeypairStrings,
+  EddsaKeyPairStrings,
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
@@ -50,7 +50,7 @@ interface KycTestEnv {
   exchangeBankAccount: HarnessExchangeBankAccount;
   walletClient: WalletClient;
   walletService: WalletService;
-  amlKeypair: EddsaKeypairStrings;
+  amlKeypair: EddsaKeyPairStrings;
 }
 
 async function createKycTestkudosEnvironment(
diff --git 
a/packages/taler-harness/src/integrationtests/test-kyc-form-withdrawal.ts 
b/packages/taler-harness/src/integrationtests/test-kyc-form-withdrawal.ts
index 5d4211c9f..357332deb 100644
--- a/packages/taler-harness/src/integrationtests/test-kyc-form-withdrawal.ts
+++ b/packages/taler-harness/src/integrationtests/test-kyc-form-withdrawal.ts
@@ -32,7 +32,7 @@ import {
 import { readResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
 import {
   createSyncCryptoApi,
-  EddsaKeypairStrings,
+  EddsaKeyPairStrings,
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
@@ -57,7 +57,7 @@ interface KycTestEnv {
   exchangeBankAccount: HarnessExchangeBankAccount;
   walletClient: WalletClient;
   walletService: WalletService;
-  amlKeypair: EddsaKeypairStrings;
+  amlKeypair: EddsaKeyPairStrings;
 }
 
 async function createKycTestkudosEnvironment(
diff --git 
a/packages/taler-harness/src/integrationtests/test-kyc-new-measure.ts 
b/packages/taler-harness/src/integrationtests/test-kyc-new-measure.ts
index 7af36502a..97e6a9121 100644
--- a/packages/taler-harness/src/integrationtests/test-kyc-new-measure.ts
+++ b/packages/taler-harness/src/integrationtests/test-kyc-new-measure.ts
@@ -33,7 +33,7 @@ import {
 import { readResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
 import {
   createSyncCryptoApi,
-  EddsaKeypairStrings,
+  EddsaKeyPairStrings,
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
@@ -62,7 +62,7 @@ interface KycTestEnv {
   exchangeBankAccount: HarnessExchangeBankAccount;
   walletClient: WalletClient;
   walletService: WalletService;
-  amlKeypair: EddsaKeypairStrings;
+  amlKeypair: EddsaKeyPairStrings;
 }
 
 async function createKycTestkudosEnvironment(
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 2205ee687..0496a51cb 100644
--- a/packages/taler-harness/src/integrationtests/test-kyc-peer-pull.ts
+++ b/packages/taler-harness/src/integrationtests/test-kyc-peer-pull.ts
@@ -30,7 +30,7 @@ import {
 } from "@gnu-taler/taler-util";
 import {
   createSyncCryptoApi,
-  EddsaKeypairStrings,
+  EddsaKeyPairStrings,
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
@@ -59,7 +59,7 @@ interface KycTestEnv {
   exchangeBankAccount: HarnessExchangeBankAccount;
   walletClient: WalletClient;
   walletService: WalletService;
-  amlKeypair: EddsaKeypairStrings;
+  amlKeypair: EddsaKeyPairStrings;
 }
 
 async function createKycTestkudosEnvironment(
diff --git a/packages/taler-harness/src/integrationtests/test-kyc-peer-push.ts 
b/packages/taler-harness/src/integrationtests/test-kyc-peer-push.ts
index ed880251d..465279c28 100644
--- a/packages/taler-harness/src/integrationtests/test-kyc-peer-push.ts
+++ b/packages/taler-harness/src/integrationtests/test-kyc-peer-push.ts
@@ -29,7 +29,7 @@ import {
 } from "@gnu-taler/taler-util";
 import {
   createSyncCryptoApi,
-  EddsaKeypairStrings,
+  EddsaKeyPairStrings,
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
@@ -58,7 +58,7 @@ interface KycTestEnv {
   exchangeBankAccount: HarnessExchangeBankAccount;
   walletClient: WalletClient;
   walletService: WalletService;
-  amlKeypair: EddsaKeypairStrings;
+  amlKeypair: EddsaKeyPairStrings;
 }
 
 async function createKycTestkudosEnvironment(
diff --git 
a/packages/taler-harness/src/integrationtests/test-kyc-threshold-withdrawal.ts 
b/packages/taler-harness/src/integrationtests/test-kyc-threshold-withdrawal.ts
index 27073ab2a..7861fae97 100644
--- 
a/packages/taler-harness/src/integrationtests/test-kyc-threshold-withdrawal.ts
+++ 
b/packages/taler-harness/src/integrationtests/test-kyc-threshold-withdrawal.ts
@@ -28,7 +28,7 @@ import {
 } from "@gnu-taler/taler-util";
 import {
   createSyncCryptoApi,
-  EddsaKeypairStrings,
+  EddsaKeyPairStrings,
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
@@ -52,7 +52,7 @@ interface KycTestEnv {
   exchangeBankAccount: HarnessExchangeBankAccount;
   walletClient: WalletClient;
   walletService: WalletService;
-  amlKeypair: EddsaKeypairStrings;
+  amlKeypair: EddsaKeyPairStrings;
 }
 
 async function createKycTestkudosEnvironment(
diff --git a/packages/taler-util/src/types-taler-exchange.ts 
b/packages/taler-util/src/types-taler-exchange.ts
index bc8165991..2bff19063 100644
--- a/packages/taler-util/src/types-taler-exchange.ts
+++ b/packages/taler-util/src/types-taler-exchange.ts
@@ -1617,6 +1617,14 @@ export interface LegitimizationNeededResponse {
   // should use the number to check for the account's AML/KYC status
   // using the /kyc-check/$REQUIREMENT_ROW endpoint.
   requirement_row: Integer | undefined;
+
+  // True if the operation was denied because the
+  // KYC auth key does not match the merchant public
+  // key.  In this case, a KYC auth wire transfer
+  // with the merchant public key must be performed
+  // first.
+  // Since exchange protocol **v21**.
+  bad_kyc_auth?: boolean;
 }
 
 export interface AccountKycStatus {
@@ -2423,6 +2431,7 @@ export const codecForLegitimizationNeededResponse =
       .property("h_payto", codecForString())
       .property("account_pub", codecOptional(codecForString()))
       .property("requirement_row", codecOptional(codecForNumber()))
+      .property("bad_kyc_auth", codecOptional(codecForBoolean()))
       .build("TalerExchangeApi.LegitimizationNeededResponse");
 
 export const codecForAccountKycStatus = (): Codec<AccountKycStatus> =>
diff --git a/packages/taler-util/src/types-taler-wallet-transactions.ts 
b/packages/taler-util/src/types-taler-wallet-transactions.ts
index 675878e0c..8d01e7fdf 100644
--- a/packages/taler-util/src/types-taler-wallet-transactions.ts
+++ b/packages/taler-util/src/types-taler-wallet-transactions.ts
@@ -130,6 +130,7 @@ export enum TransactionMinorState {
   MergeKycRequired = "merge-kyc",
   BalanceKycRequired = "balance-kyc",
   BalanceKycInit = "balance-kyc-init",
+  KycAuthRequired = "kyc-auth",
   Track = "track",
   SubmitPayment = "submit-payment",
   RebindSession = "rebind-session",
diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts 
b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
index ce6193b83..6280795e8 100644
--- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
+++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
@@ -170,7 +170,7 @@ export interface TalerCryptoInterface {
     req: ContractTermsValidationRequest,
   ): Promise<ValidationResult>;
 
-  createEddsaKeypair(req: {}): Promise<EddsaKeypairStrings>;
+  createEddsaKeypair(req: {}): Promise<EddsaKeyPairStrings>;
 
   eddsaGetPublic(req: EddsaGetPublicRequest): Promise<EddsaGetPublicResponse>;
 
@@ -333,12 +333,12 @@ export const nullCrypto: TalerCryptoInterface = {
   ): Promise<ValidationResult> {
     throw new Error("Function not implemented.");
   },
-  createEddsaKeypair: function (req: unknown): Promise<EddsaKeypairStrings> {
+  createEddsaKeypair: function (req: unknown): Promise<EddsaKeyPairStrings> {
     throw new Error("Function not implemented.");
   },
   eddsaGetPublic: function (
     req: EddsaGetPublicRequest,
-  ): Promise<EddsaKeypairStrings> {
+  ): Promise<EddsaKeyPairStrings> {
     throw new Error("Function not implemented.");
   },
   unblindDenominationSignature: function (
@@ -602,7 +602,7 @@ export interface WireAccountValidationRequest {
   creditRestrictions?: any[];
 }
 
-export interface EddsaKeypairStrings {
+export interface EddsaKeyPairStrings {
   priv: string;
   pub: string;
 }
@@ -1085,7 +1085,7 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
    */
   async createEddsaKeypair(
     tci: TalerCryptoInterfaceR,
-  ): Promise<EddsaKeypairStrings> {
+  ): Promise<EddsaKeyPairStrings> {
     const eddsaPriv = encodeCrock(getRandomBytes(32));
     const eddsaPubRes = await tci.eddsaGetPublic(tci, {
       priv: eddsaPriv,
@@ -1099,7 +1099,7 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
   async eddsaGetPublic(
     tci: TalerCryptoInterfaceR,
     req: EddsaGetPublicRequest,
-  ): Promise<EddsaKeypairStrings> {
+  ): Promise<EddsaKeyPairStrings> {
     return {
       priv: req.priv,
       pub: encodeCrock(eddsaGetPublic(decodeCrock(req.priv))),
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index ba33c5555..a42548bb3 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -1736,6 +1736,9 @@ export enum DepositOperationStatus {
   PendingDepositKyc = 0x0100_0003,
   SuspendedDepositKyc = 0x0110_0003,
 
+  PendingDepositKycAuth = 0x0100_0005,
+  SuspendedDepositKycAuth = 0x0110_0005,
+
   Aborting = 0x0103_0000,
   SuspendedAborting = 0x0113_0000,
 
diff --git a/packages/taler-wallet-core/src/deposits.ts 
b/packages/taler-wallet-core/src/deposits.ts
index 371d7cf70..3bac319cd 100644
--- a/packages/taler-wallet-core/src/deposits.ts
+++ b/packages/taler-wallet-core/src/deposits.ts
@@ -111,7 +111,7 @@ import {
   getExchangeWireFee,
   getScopeForAllExchanges,
 } from "./exchanges.js";
-import { EddsaKeypairStrings } from "./index.js";
+import { EddsaKeyPairStrings } from "./index.js";
 import {
   extractContractData,
   generateDepositPermissions,
@@ -301,6 +301,7 @@ export class DepositTransactionContext implements 
TransactionContext {
           case DepositOperationStatus.SuspendedDeposit:
           case DepositOperationStatus.SuspendedDepositKyc:
           case DepositOperationStatus.SuspendedTrack:
+          case DepositOperationStatus.SuspendedDepositKycAuth:
             break;
           case DepositOperationStatus.PendingDepositKyc:
             newOpStatus = DepositOperationStatus.SuspendedDepositKyc;
@@ -317,6 +318,9 @@ export class DepositTransactionContext implements 
TransactionContext {
           case DepositOperationStatus.Aborting:
             newOpStatus = DepositOperationStatus.SuspendedAborting;
             break;
+          case DepositOperationStatus.PendingDepositKycAuth:
+            newOpStatus = DepositOperationStatus.SuspendedDepositKycAuth;
+            break;
           default:
             assertUnreachable(dg.operationStatus);
         }
@@ -398,6 +402,7 @@ export class DepositTransactionContext implements 
TransactionContext {
           case DepositOperationStatus.PendingDeposit:
           case DepositOperationStatus.PendingDepositKyc:
           case DepositOperationStatus.PendingTrack:
+          case DepositOperationStatus.PendingDepositKycAuth:
             break;
           case DepositOperationStatus.SuspendedDepositKyc:
             newOpStatus = DepositOperationStatus.PendingDepositKyc;
@@ -414,6 +419,9 @@ export class DepositTransactionContext implements 
TransactionContext {
           case DepositOperationStatus.SuspendedTrack:
             newOpStatus = DepositOperationStatus.PendingTrack;
             break;
+          case DepositOperationStatus.SuspendedDepositKycAuth:
+            newOpStatus = DepositOperationStatus.PendingDepositKycAuth;
+            break;
           default:
             assertUnreachable(dg.operationStatus);
         }
@@ -539,6 +547,18 @@ export function computeDepositTransactionStatus(
         // We lie to the UI by hiding the specific KYC state.
         minor: TransactionMinorState.KycRequired,
       };
+    case DepositOperationStatus.PendingDepositKycAuth:
+      return {
+        major: TransactionMajorState.Pending,
+        // We lie to the UI by hiding the specific KYC state.
+        minor: TransactionMinorState.KycAuthRequired,
+      };
+    case DepositOperationStatus.SuspendedDepositKycAuth:
+      return {
+        major: TransactionMajorState.Suspended,
+        // We lie to the UI by hiding the specific KYC state.
+        minor: TransactionMinorState.KycAuthRequired,
+      };
     default:
       assertUnreachable(dg.operationStatus);
   }
@@ -594,6 +614,10 @@ export function computeDepositTransactionActions(
       return [TransactionAction.Resume, TransactionAction.Abort];
     case DepositOperationStatus.SuspendedDepositKyc:
       return [TransactionAction.Suspend, TransactionAction.Abort];
+    case DepositOperationStatus.PendingDepositKycAuth:
+      return [TransactionAction.Suspend, TransactionAction.Abort];
+    case DepositOperationStatus.SuspendedDepositKycAuth:
+      return [TransactionAction.Resume, TransactionAction.Abort];
     default:
       assertUnreachable(dg.operationStatus);
   }
@@ -831,10 +855,7 @@ async function processDepositGroupPendingKyc(
   depositGroup: DepositGroupRecord,
 ): Promise<TaskRunResult> {
   const { depositGroupId } = depositGroup;
-  const transactionId = constructTransactionIdentifier({
-    tag: TransactionType.Deposit,
-    depositGroupId,
-  });
+  const ctx = new DepositTransactionContext(wex, depositGroupId);
 
   const kycInfo = depositGroup.kycInfo;
 
@@ -842,17 +863,9 @@ async function processDepositGroupPendingKyc(
     throw Error("invalid DB state, in pending(kyc), but no kycInfo present");
   }
 
-  const lastReserveKeypair = await getLastWithdrawalKeyPair(
-    wex,
-    kycInfo.exchangeBaseUrl,
-  );
-  if (!lastReserveKeypair) {
-    // Need to do a KYC transfer
-    throw Error("not supported yet");
-  }
   const sigResp = await wex.cryptoApi.signWalletKycAuth({
-    accountPriv: lastReserveKeypair.priv,
-    accountPub: lastReserveKeypair.pub,
+    accountPriv: depositGroup.merchantPriv,
+    accountPub: depositGroup.merchantPub,
   });
 
   const url = new URL(
@@ -876,8 +889,6 @@ async function processDepositGroupPendingKyc(
     },
   );
 
-  const ctx = new DepositTransactionContext(wex, depositGroupId);
-
   if (
     kycStatusRes.status === HttpStatusCode.Ok ||
     kycStatusRes.status === HttpStatusCode.NoContent
@@ -906,15 +917,113 @@ async function processDepositGroupPendingKyc(
         return { oldTxState, newTxState };
       },
     );
-    notifyTransition(wex, transactionId, transitionInfo);
+    notifyTransition(wex, ctx.transactionId, transitionInfo);
   } else if (kycStatusRes.status === HttpStatusCode.Accepted) {
     logger.info("kyc still pending");
   } else {
-    throw Error(`unexpected response from kyc-check (${kycStatusRes.status})`);
+    throwUnexpectedRequestError(
+      kycStatusRes,
+      await readTalerErrorResponse(kycStatusRes),
+    );
   }
   return TaskRunResult.backoff();
 }
 
+async function processDepositGroupPendingKycAuth(
+  wex: WalletExecutionContext,
+  depositGroup: DepositGroupRecord,
+): Promise<TaskRunResult> {
+  const { depositGroupId } = depositGroup;
+  const ctx = new DepositTransactionContext(wex, depositGroupId);
+
+  const kycInfo = depositGroup.kycInfo;
+
+  if (!kycInfo) {
+    throw Error(
+      "invalid DB state, in pending(kyc-auth), but no kycInfo present",
+    );
+  }
+
+  const sigResp = await wex.cryptoApi.signWalletKycAuth({
+    accountPriv: depositGroup.merchantPriv,
+    accountPub: depositGroup.merchantPub,
+  });
+
+  const url = new URL(
+    `kyc-check/${kycInfo.paytoHash}`,
+    kycInfo.exchangeBaseUrl,
+  );
+
+  url.searchParams.set("await_auth", "YES");
+
+  const kycStatusRes = await wex.ws.runLongpollQueueing(
+    wex,
+    url.hostname,
+    async (timeoutMs) => {
+      url.searchParams.set("timeout_ms", `${timeoutMs}`);
+      logger.info(`kyc url ${url.href}`);
+      return await wex.http.fetch(url.href, {
+        method: "GET",
+        cancellationToken: wex.cancellationToken,
+        headers: {
+          ["Account-Owner-Signature"]: sigResp.sig,
+        },
+      });
+    },
+  );
+
+  logger.info(
+    `kyc-check for auth longpoll result status: ${kycStatusRes.status}`,
+  );
+
+  switch (kycStatusRes.status) {
+    case HttpStatusCode.Ok:
+      return await transitionKycAuthSuccess(ctx);
+    case HttpStatusCode.NoContent:
+      return await transitionKycAuthSuccess(ctx);
+    case HttpStatusCode.Accepted:
+      logger.info("kyc still pending");
+      return TaskRunResult.longpollReturnedPending();
+    default:
+      throwUnexpectedRequestError(
+        kycStatusRes,
+        await readTalerErrorResponse(kycStatusRes),
+      );
+  }
+}
+
+async function transitionKycAuthSuccess(
+  ctx: DepositTransactionContext,
+): Promise<TaskRunResult> {
+  const transitionInfo = await ctx.wex.db.runReadWriteTx(
+    { storeNames: ["depositGroups", "transactionsMeta"] },
+    async (tx) => {
+      const newDg = await tx.depositGroups.get(ctx.depositGroupId);
+      if (!newDg) {
+        return;
+      }
+      const oldTxState = computeDepositTransactionStatus(newDg);
+      switch (newDg.operationStatus) {
+        case DepositOperationStatus.PendingDepositKycAuth:
+          newDg.operationStatus = DepositOperationStatus.PendingDeposit;
+          break;
+        default:
+          return;
+      }
+      await tx.depositGroups.put(newDg);
+      await ctx.updateTransactionMeta(tx);
+      const newTxState = computeDepositTransactionStatus(newDg);
+      return { oldTxState, newTxState };
+    },
+  );
+  notifyTransition(ctx.wex, ctx.transactionId, transitionInfo);
+  if (transitionInfo) {
+    return TaskRunResult.progress();
+  } else {
+    return TaskRunResult.backoff();
+  }
+}
+
 /**
  * Finds the reserve key pair of the most recent withdrawal
  * with the given exchange.
@@ -923,9 +1032,9 @@ async function processDepositGroupPendingKyc(
 async function getLastWithdrawalKeyPair(
   wex: WalletExecutionContext,
   exchangeBaseUrl: string,
-): Promise<EddsaKeypairStrings | undefined> {
+): Promise<EddsaKeyPairStrings | undefined> {
   let candidateTimestamp: AbsoluteTime | undefined = undefined;
-  let candidateRes: EddsaKeypairStrings | undefined = undefined;
+  let candidateRes: EddsaKeyPairStrings | undefined = undefined;
   await wex.db.runAllStoresReadOnlyTx({}, async (tx) => {
     const withdrawalRecs =
       await tx.withdrawalGroups.indexes.byExchangeBaseUrl.getAll(
@@ -966,14 +1075,9 @@ async function transitionToKycRequired(
 
   const ctx = new DepositTransactionContext(wex, depositGroupId);
 
-  const lastReserveKeypair = await getLastWithdrawalKeyPair(wex, exchangeUrl);
-  if (!lastReserveKeypair) {
-    // Need to do a KYC transfer
-    throw Error("not supported yet");
-  }
   const sigResp = await wex.cryptoApi.signWalletKycAuth({
-    accountPriv: lastReserveKeypair.priv,
-    accountPub: lastReserveKeypair.pub,
+    accountPriv: depositGroup.merchantPriv,
+    accountPub: depositGroup.merchantPub,
   });
 
   const url = new URL(`kyc-check/${kycPaytoHash}`, exchangeUrl);
@@ -1032,6 +1136,48 @@ async function transitionToKycRequired(
   }
 }
 
+async function transitionToKycAuthRequired(
+  wex: WalletExecutionContext,
+  depositGroup: DepositGroupRecord,
+  kycPaytoHash: string,
+  exchangeUrl: string,
+): Promise<TaskRunResult> {
+  const { depositGroupId } = depositGroup;
+
+  const ctx = new DepositTransactionContext(wex, depositGroupId);
+
+  const transitionInfo = await wex.db.runReadWriteTx(
+    { storeNames: ["depositGroups", "transactionsMeta"] },
+    async (tx) => {
+      const dg = await tx.depositGroups.get(depositGroupId);
+      if (!dg) {
+        return undefined;
+      }
+      const oldTxState = computeDepositTransactionStatus(dg);
+      switch (dg.operationStatus) {
+        case DepositOperationStatus.PendingTrack:
+          throw Error("not yet supported");
+          break;
+        case DepositOperationStatus.PendingDeposit:
+          dg.operationStatus = DepositOperationStatus.PendingDepositKycAuth;
+          break;
+        default:
+          return;
+      }
+      dg.kycInfo = {
+        exchangeBaseUrl: exchangeUrl,
+        paytoHash: kycPaytoHash,
+      };
+      await tx.depositGroups.put(dg);
+      await ctx.updateTransactionMeta(tx);
+      const newTxState = computeDepositTransactionStatus(dg);
+      return { oldTxState, newTxState };
+    },
+  );
+  notifyTransition(wex, ctx.transactionId, transitionInfo);
+  return TaskRunResult.progress();
+}
+
 async function processDepositGroupPendingTrack(
   wex: WalletExecutionContext,
   depositGroup: DepositGroupRecord,
@@ -1399,12 +1545,21 @@ async function processDepositGroupPendingDeposit(
         logger.info(
           `kyc legitimization needed response: ${j2s(kycLegiNeededResp)}`,
         );
-        return transitionToKycRequired(
-          wex,
-          depositGroup,
-          kycLegiNeededResp.h_payto,
-          exchangeBaseUrl,
-        );
+        if (kycLegiNeededResp.bad_kyc_auth) {
+          return transitionToKycAuthRequired(
+            wex,
+            depositGroup,
+            kycLegiNeededResp.h_payto,
+            exchangeBaseUrl,
+          );
+        } else {
+          return transitionToKycRequired(
+            wex,
+            depositGroup,
+            kycLegiNeededResp.h_payto,
+            exchangeBaseUrl,
+          );
+        }
       }
     }
 
@@ -1488,6 +1643,8 @@ export async function processDepositGroup(
       return processDepositGroupPendingDeposit(wex, depositGroup);
     case DepositOperationStatus.Aborting:
       return processDepositGroupAborting(wex, depositGroup);
+    case DepositOperationStatus.PendingDepositKycAuth:
+      return processDepositGroupPendingKycAuth(wex, depositGroup);
   }
 
   return TaskRunResult.finished();
@@ -1544,8 +1701,9 @@ async function trackDeposit(
       return { type: "wired", ...wired };
     }
     default: {
-      throw Error(
-        `unexpected response from track-transaction (${httpResp.status})`,
+      throwUnexpectedRequestError(
+        httpResp,
+        await readTalerErrorResponse(httpResp),
       );
     }
   }
@@ -1700,8 +1858,8 @@ export async function createDepositGroup(
   wex: WalletExecutionContext,
   req: CreateDepositGroupRequest,
 ): Promise<CreateDepositGroupResponse> {
-  const p = parsePaytoUri(req.depositPaytoUri);
-  if (!p) {
+  const depositPayto = parsePaytoUri(req.depositPaytoUri);
+  if (!depositPayto) {
     throw Error("invalid payto URI");
   }
 
@@ -1732,15 +1890,68 @@ export async function createDepositGroup(
     AbsoluteTime.addDuration(now, Duration.fromSpec({ minutes: 5 })),
   );
   const nowRounded = AbsoluteTime.toProtocolTimestamp(now);
+
+  const payCoinSel = await selectPayCoins(wex, {
+    restrictExchanges: {
+      auditors: [],
+      exchanges: exchangeInfos.map((x) => ({
+        exchangeBaseUrl: x.url,
+        exchangePub: x.master_pub,
+      })),
+    },
+    restrictWireMethod: depositPayto.targetType,
+    contractTermsAmount: amount,
+    depositFeeLimit: amount,
+    prevPayCoins: [],
+  });
+
+  let coins: SelectedProspectiveCoin[] | undefined = undefined;
+
+  switch (payCoinSel.type) {
+    case "success":
+      coins = payCoinSel.coinSel.coins;
+      break;
+    case "failure":
+      throw TalerError.fromDetail(
+        TalerErrorCode.WALLET_DEPOSIT_GROUP_INSUFFICIENT_BALANCE,
+        {
+          insufficientBalanceDetails: payCoinSel.insufficientBalanceDetails,
+        },
+      );
+    case "prospective":
+      coins = payCoinSel.result.prospectiveCoins;
+      break;
+    default:
+      assertUnreachable(payCoinSel);
+  }
+
+  // Heuristic for the merchant key pair: If there's an exchange where we made
+  // a withdrawal from, use that key pair, so the user doesn't have to do
+  // a KYC transfer to establish a kyc accout key pair.
+  // FIXME: Extend the heuristic to use the last used merchant key pair?
+  let merchantPair: EddsaKeyPairStrings | undefined = undefined;
+  if (coins.length > 0) {
+    const res = await getLastWithdrawalKeyPair(wex, coins[0].exchangeBaseUrl);
+    if (res) {
+      logger.info(
+        `reusing reserve pub ${res.pub} from last withdrawal to 
${coins[0].exchangeBaseUrl}`,
+      );
+      merchantPair = res;
+    }
+  }
+  if (!merchantPair) {
+    logger.info(`creating new merchant key pair for deposit`);
+    merchantPair = await wex.cryptoApi.createEddsaKeypair({});
+  }
+
   const noncePair = await wex.cryptoApi.createEddsaKeypair({});
-  const merchantPair = await wex.cryptoApi.createEddsaKeypair({});
   const wireSalt = encodeCrock(getRandomBytes(16));
   const wireHash = hashWire(req.depositPaytoUri, wireSalt);
   const contractTerms: MerchantContractTerms = {
     exchanges: exchangeInfos,
     amount: req.amount,
     max_fee: Amounts.stringify(amount),
-    wire_method: p.targetType,
+    wire_method: depositPayto.targetType,
     timestamp: nowRounded,
     merchant_base_url: "",
     summary: "",
@@ -1768,37 +1979,6 @@ export async function createDepositGroup(
     "",
   );
 
-  const payCoinSel = await selectPayCoins(wex, {
-    restrictExchanges: {
-      auditors: [],
-      exchanges: contractData.allowedExchanges,
-    },
-    restrictWireMethod: contractData.wireMethod,
-    contractTermsAmount: Amounts.parseOrThrow(contractData.amount),
-    depositFeeLimit: Amounts.parseOrThrow(contractData.maxDepositFee),
-    prevPayCoins: [],
-  });
-
-  let coins: SelectedProspectiveCoin[] | undefined = undefined;
-
-  switch (payCoinSel.type) {
-    case "success":
-      coins = payCoinSel.coinSel.coins;
-      break;
-    case "failure":
-      throw TalerError.fromDetail(
-        TalerErrorCode.WALLET_DEPOSIT_GROUP_INSUFFICIENT_BALANCE,
-        {
-          insufficientBalanceDetails: payCoinSel.insufficientBalanceDetails,
-        },
-      );
-    case "prospective":
-      coins = payCoinSel.result.prospectiveCoins;
-      break;
-    default:
-      assertUnreachable(payCoinSel);
-  }
-
   const totalDepositCost = await getTotalPaymentCost(wex, currency, coins);
 
   let depositGroupId: string;
@@ -1830,7 +2010,11 @@ export async function createDepositGroup(
   }
 
   const counterpartyEffectiveDepositAmount =
-    await getCounterpartyEffectiveDepositAmount(wex, p.targetType, coins);
+    await getCounterpartyEffectiveDepositAmount(
+      wex,
+      depositPayto.targetType,
+      coins,
+    );
 
   const depositGroup: DepositGroupRecord = {
     contractTermsHash,
diff --git a/packages/taler-wallet-core/src/pay-merchant.ts 
b/packages/taler-wallet-core/src/pay-merchant.ts
index 12cfedc9e..8744fc5d1 100644
--- a/packages/taler-wallet-core/src/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/pay-merchant.ts
@@ -123,7 +123,7 @@ import {
   TransactionContext,
   TransitionResultType,
 } from "./common.js";
-import { EddsaKeypairStrings } from "./crypto/cryptoImplementation.js";
+import { EddsaKeyPairStrings } from "./crypto/cryptoImplementation.js";
 import {
   CoinRecord,
   DbCoinSelection,
@@ -1196,7 +1196,7 @@ async function createOrReusePurchase(
     return oldProposal.proposalId;
   }
 
-  let noncePair: EddsaKeypairStrings;
+  let noncePair: EddsaKeyPairStrings;
   let shared = false;
   if (noncePriv) {
     shared = true;
diff --git a/packages/taler-wallet-core/src/withdraw.ts 
b/packages/taler-wallet-core/src/withdraw.ts
index 1ed600265..6c9bcac63 100644
--- a/packages/taler-wallet-core/src/withdraw.ts
+++ b/packages/taler-wallet-core/src/withdraw.ts
@@ -129,7 +129,7 @@ import {
   requireExchangeTosAcceptedOrThrow,
   runWithClientCancellation,
 } from "./common.js";
-import { EddsaKeypairStrings } from "./crypto/cryptoImplementation.js";
+import { EddsaKeyPairStrings } from "./crypto/cryptoImplementation.js";
 import {
   CoinRecord,
   CoinSourceType,
@@ -3060,7 +3060,7 @@ export async function 
internalPrepareCreateWithdrawalGroup(
     exchangeBaseUrl: string | undefined;
     forcedWithdrawalGroupId?: string;
     forcedDenomSel?: ForcedDenomSel;
-    reserveKeyPair?: EddsaKeypairStrings;
+    reserveKeyPair?: EddsaKeyPairStrings;
     restrictAge?: number;
     wgInfo: WgInfo;
   },
@@ -3256,7 +3256,7 @@ export async function internalCreateWithdrawalGroup(
     amount?: AmountJson;
     forcedWithdrawalGroupId?: string;
     forcedDenomSel?: ForcedDenomSel;
-    reserveKeyPair?: EddsaKeypairStrings;
+    reserveKeyPair?: EddsaKeyPairStrings;
     restrictAge?: number;
     wgInfo: WgInfo;
   },
@@ -3846,7 +3846,7 @@ export async function createManualWithdrawal(
     );
   }
 
-  let reserveKeyPair: EddsaKeypairStrings;
+  let reserveKeyPair: EddsaKeyPairStrings;
   if (req.forceReservePriv) {
     const pubResp = await wex.cryptoApi.eddsaGetPublic({
       priv: req.forceReservePriv,

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