commit c3ebf7aca5dc33fb342b4e9cbd21d12b8dc090bf
parent 285ba92711f4998966b7be3615823c50a6ebcdd1
Author: Christian Grothoff <christian@grothoff.org>
Date: Sat, 20 Jul 2024 17:09:57 +0200
new test command for KYC wire transfers
Diffstat:
6 files changed, 423 insertions(+), 31 deletions(-)
diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h
@@ -835,12 +835,13 @@ TALER_TESTING_cmd_deposit_confirmation_with_retry (
/**
- * Create /admin/add-incoming command.
+ * Create command that does a wire transfer using
+ * /admin/add-incoming to establish a reserve.
*
* @param label command label.
* @param amount amount to transfer.
- * @param payto_debit_account which account sends money.
* @param auth authentication data
+ * @param payto_debit_account which account sends money.
* @return the command.
*/
struct TALER_TESTING_Command
@@ -852,6 +853,27 @@ TALER_TESTING_cmd_admin_add_incoming (
/**
+ * Create command that does a wire transfer using
+ * /admin/add-kycauth to establish an account private key.
+ *
+ * @param label command label.
+ * @param amount amount to transfer.
+ * @param auth authentication data
+ * @param payto_debit_account which account sends money.
+ * @param account_ref reference to command with account
+ * private key to use; NULL to create a fresh key pair
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_admin_add_kycauth (
+ const char *label,
+ const char *amount,
+ const struct TALER_BANK_AuthenticationData *auth,
+ const char *payto_debit_account,
+ const char *account_ref);
+
+
+/**
* Create "fakebank transfer" CMD, letting the caller specify
* a reference to a command that can offer a reserve private key.
* This private key will then be used to construct the subject line
@@ -2182,12 +2204,14 @@ TALER_TESTING_cmd_wallet_kyc_get (const char *label,
*
* @param label command label.
* @param payment_target_reference command with a payment target to query
+ * @param account_reference command with account private key to query
* @param expected_response_code expected HTTP status
* @return the command
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_check_kyc_get (const char *label,
const char *payment_target_reference,
+ const char *account_reference,
unsigned int expected_response_code);
diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c
@@ -2212,7 +2212,7 @@ TALER_KYCLOGIC_kyc_done (void)
GNUNET_array_grow (ap->required_contexts,
ap->num_required_contexts,
0);
- for (unsigned int j = 0; i<ap->num_required_attributes; j++)
+ for (unsigned int j = 0; j<ap->num_required_attributes; j++)
GNUNET_free (ap->required_attributes[j]);
GNUNET_array_grow (ap->required_attributes,
ap->num_required_attributes,
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
@@ -48,6 +48,7 @@ libtalertesting_la_SOURCES = \
testing_api_cmd_auditor_exec_auditor.c \
testing_api_cmd_auditor_exec_auditor_dbinit.c \
testing_api_cmd_bank_admin_add_incoming.c \
+ testing_api_cmd_bank_admin_add_kycauth.c \
testing_api_cmd_bank_check.c \
testing_api_cmd_bank_admin_check.c \
testing_api_cmd_bank_check_empty.c \
diff --git a/src/testing/testing_api_cmd_bank_admin_add_incoming.c b/src/testing/testing_api_cmd_bank_admin_add_incoming.c
@@ -27,7 +27,6 @@
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
#include "taler_signatures.h"
#include "taler_testing_lib.h"
@@ -45,7 +44,7 @@
/**
- * State for a "fakebank transfer" CMD.
+ * State for a "bank transfer" CMD.
*/
struct AdminAddIncomingState
{
@@ -92,7 +91,7 @@ struct AdminAddIncomingState
struct TALER_ReservePublicKeyP reserve_pub;
/**
- * Handle to the pending request at the fakebank.
+ * Handle to the pending request at the bank.
*/
struct TALER_BANK_AdminAddIncomingHandle *aih;
@@ -120,19 +119,6 @@ struct AdminAddIncomingState
struct GNUNET_TIME_Timestamp timestamp;
/**
- * Merchant instance. Sometimes used to get the tip reserve
- * private key by reading the appropriate config section.
- */
- const char *instance;
-
- /**
- * Configuration filename. Used to get the tip reserve key
- * filename (used to obtain a public key to write in the
- * transfer subject).
- */
- const char *config_filename;
-
- /**
* Task scheduled to try later.
*/
struct GNUNET_SCHEDULER_Task *retry_task;
@@ -157,7 +143,7 @@ struct AdminAddIncomingState
/**
- * Run the "fakebank transfer" CMD.
+ * Run the "bank transfer" CMD.
*
* @param cls closure.
* @param cmd CMD being run.
@@ -188,7 +174,7 @@ do_retry (void *cls)
/**
- * This callback will process the fakebank response to the wire
+ * This callback will process the bank response to the wire
* transfer. It just checks whether the HTTP response code is
* acceptable.
*
@@ -205,10 +191,10 @@ confirmation_cb (void *cls,
fts->aih = NULL;
/**
* Test case not caring about the HTTP status code.
- * That helps when Fakebank and Libeufin diverge in
+ * That helps when fakebank and Libeufin diverge in
* the response status code. An example is the
* /admin/add-incoming: libeufin return ALWAYS '200 OK'
- * (see note below) whereas the Fakebank responds with
+ * (see note below) whereas the fakebank responds with
* '409 Conflict' upon a duplicate reserve public key.
*
* Note: this decision aims at avoiding to put Taler
@@ -270,7 +256,7 @@ confirmation_cb (void *cls,
{
GNUNET_log (
GNUNET_ERROR_TYPE_INFO,
- "Retrying fakebank transfer failed with %u/%d\n",
+ "Retrying bank transfer failed with %u/%d\n",
air->http_status,
(int) air->ec);
/* on DB conflicts, do not use backoff */
@@ -291,7 +277,7 @@ confirmation_cb (void *cls,
}
GNUNET_break (0);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Fakebank returned HTTP status %u/%d\n",
+ "Bank returned HTTP status %u/%d\n",
air->http_status,
(int) air->ec);
TALER_TESTING_interpreter_fail (is);
@@ -299,7 +285,7 @@ confirmation_cb (void *cls,
/**
- * Run the "fakebank transfer" CMD.
+ * Run the "bank transfer" CMD.
*
* @param cls closure.
* @param cmd CMD being run.
@@ -354,7 +340,7 @@ admin_add_incoming_run (void *cls,
}
else
{
- /* No referenced reserve, no instance to take priv
+ /* No referenced reserve to take priv
* from, no explicit subject given: create new key! */
GNUNET_CRYPTO_eddsa_key_create (&fts->reserve_priv.eddsa_priv);
fts->reserve_priv_known = true;
@@ -578,11 +564,11 @@ TALER_TESTING_cmd_admin_add_incoming_with_ref (
/**
- * Modify a fakebank transfer command to enable retries when the
+ * Modify a bank transfer command to enable retries when the
* reserve is not yet full or we get other transient errors from the
- * fakebank.
+ * bank.
*
- * @param cmd a fakebank transfer command
+ * @param cmd a bank transfer command
* @return the command with retries enabled
*/
struct TALER_TESTING_Command
diff --git a/src/testing/testing_api_cmd_bank_admin_add_kycauth.c b/src/testing/testing_api_cmd_bank_admin_add_kycauth.c
@@ -0,0 +1,364 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_bank_admin_add_kycauth.c
+ * @brief implementation of a bank /admin/add-kycauth command
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "backoff.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_bank_service.h"
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a KYCAUTH wire transfer CMD.
+ */
+struct AdminAddKycauthState
+{
+
+ /**
+ * Label of any command that can trait-offer an account priv.
+ */
+ const char *account_ref;
+
+ /**
+ * Wire transfer amount.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Base URL of the credited account.
+ */
+ const char *exchange_credit_url;
+
+ /**
+ * Money sender payto URL.
+ */
+ const char *payto_debit_account;
+
+ /**
+ * Username to use for authentication.
+ */
+ struct TALER_BANK_AuthenticationData auth;
+
+ /**
+ * Set (by the interpreter) to the account's private key
+ * we used to make a wire transfer subject line with.
+ */
+ union TALER_AccountPrivateKeyP account_priv;
+
+ /**
+ * Account public key matching @e account_priv.
+ */
+ union TALER_AccountPublicKeyP account_pub;
+
+ /**
+ * Handle to the pending request at the bank.
+ */
+ struct TALER_BANK_AdminAddKycauthHandle *aih;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Set to the wire transfer's unique ID.
+ */
+ uint64_t serial_id;
+
+ /**
+ * Timestamp of the transaction (as returned from the bank).
+ */
+ struct GNUNET_TIME_Timestamp timestamp;
+
+ /**
+ * Expected HTTP status code.
+ */
+ unsigned int expected_http_status;
+};
+
+
+/**
+ * This callback will process the bank response to the wire
+ * transfer. It just checks whether the HTTP response code is
+ * acceptable.
+ *
+ * @param cls closure with the interpreter state
+ * @param air response details
+ */
+static void
+confirmation_cb (void *cls,
+ const struct TALER_BANK_AdminAddKycauthResponse *air)
+{
+ struct AdminAddKycauthState *fts = cls;
+ struct TALER_TESTING_Interpreter *is = fts->is;
+
+ fts->aih = NULL;
+ if (air->http_status != fts->expected_http_status)
+ {
+ TALER_TESTING_unexpected_status (is,
+ air->http_status,
+ fts->expected_http_status);
+ return;
+ }
+ switch (air->http_status)
+ {
+ case MHD_HTTP_OK:
+ fts->serial_id
+ = air->details.ok.serial_id;
+ fts->timestamp
+ = air->details.ok.timestamp;
+ TALER_TESTING_interpreter_next (is);
+ return;
+ case MHD_HTTP_UNAUTHORIZED:
+ switch (fts->auth.method)
+ {
+ case TALER_BANK_AUTH_NONE:
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Authentication required, but none configure.\n");
+ break;
+ case TALER_BANK_AUTH_BASIC:
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Basic authentication (%s) failed.\n",
+ fts->auth.details.basic.username);
+ break;
+ }
+ break;
+ case MHD_HTTP_CONFLICT:
+ TALER_TESTING_interpreter_next (is);
+ return;
+ default:
+ GNUNET_break (0);
+ break;
+ }
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Bank returned HTTP status %u/%d\n",
+ air->http_status,
+ (int) air->ec);
+ TALER_TESTING_interpreter_fail (is);
+}
+
+
+/**
+ * Run the KYC AUTH transfer CMD.
+ *
+ * @param cls closure.
+ * @param cmd CMD being run.
+ * @param is interpreter state.
+ */
+static void
+admin_add_kycauth_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AdminAddKycauthState *fts = cls;
+
+ (void) cmd;
+ fts->is = is;
+ /* Use account public key as subject */
+ if (NULL != fts->account_ref)
+ {
+ const struct TALER_TESTING_Command *ref;
+ const union TALER_AccountPrivateKeyP *account_priv;
+
+ ref = TALER_TESTING_interpreter_lookup_command (
+ is,
+ fts->account_ref);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_account_priv (ref,
+ &account_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ fts->account_priv = *account_priv;
+ }
+ else
+ {
+ /* No referenced account, no instance to take priv
+ * from, no explicit subject given: create new key! */
+ GNUNET_CRYPTO_eddsa_key_create (
+ &fts->account_priv.merchant_priv.eddsa_priv);
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (
+ &fts->account_priv.merchant_priv.eddsa_priv,
+ &fts->account_pub.merchant_pub.eddsa_pub);
+ fts->aih
+ = TALER_BANK_admin_add_kycauth (
+ TALER_TESTING_interpreter_get_context (is),
+ &fts->auth,
+ &fts->account_pub,
+ &fts->amount,
+ fts->payto_debit_account,
+ &confirmation_cb,
+ fts);
+ if (NULL == fts->aih)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "/admin/add-kycauth" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure
+ * @param cmd current CMD being cleaned up.
+ */
+static void
+admin_add_kycauth_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AdminAddKycauthState *fts = cls;
+
+ if (NULL != fts->aih)
+ {
+ TALER_TESTING_command_incomplete (fts->is,
+ cmd->label);
+ TALER_BANK_admin_add_kycauth_cancel (fts->aih);
+ fts->aih = NULL;
+ }
+ GNUNET_free (fts);
+}
+
+
+/**
+ * Offer internal data from a "/admin/add-kycauth" CMD to other
+ * commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+admin_add_kycauth_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct AdminAddKycauthState *fts = cls;
+ static const char *void_uri = "payto://void/the-exchange";
+
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_bank_row (&fts->serial_id),
+ TALER_TESTING_make_trait_debit_payto_uri (fts->payto_debit_account),
+ TALER_TESTING_make_trait_payto_uri (fts->payto_debit_account),
+ /* Used as a marker, content does not matter */
+ TALER_TESTING_make_trait_credit_payto_uri (void_uri),
+ TALER_TESTING_make_trait_exchange_bank_account_url (
+ fts->exchange_credit_url),
+ TALER_TESTING_make_trait_amount (&fts->amount),
+ TALER_TESTING_make_trait_timestamp (0,
+ &fts->timestamp),
+ TALER_TESTING_make_trait_account_priv (&fts->account_priv),
+ TALER_TESTING_make_trait_account_pub (&fts->account_pub),
+ TALER_TESTING_trait_end ()
+ };
+
+ if (MHD_HTTP_OK !=
+ fts->expected_http_status)
+ return GNUNET_NO; /* requests that failed generate no history */
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Create internal state for "/admin/add-kycauth" CMD.
+ *
+ * @param amount the amount to transfer.
+ * @param payto_debit_account which account sends money
+ * @param auth authentication data
+ * @param account_ref reference to command with account
+ * private key to use; NULL to create a fresh key pair
+ * @return the internal state
+ */
+static struct AdminAddKycauthState *
+make_fts (const char *amount,
+ const struct TALER_BANK_AuthenticationData *auth,
+ const char *payto_debit_account,
+ const char *account_ref)
+{
+ struct AdminAddKycauthState *fts;
+
+ fts = GNUNET_new (struct AdminAddKycauthState);
+ fts->exchange_credit_url = auth->wire_gateway_url;
+ fts->payto_debit_account = payto_debit_account;
+ fts->account_ref = account_ref;
+ fts->auth = *auth;
+ fts->expected_http_status = MHD_HTTP_OK;
+ if (GNUNET_OK !=
+ TALER_string_to_amount (amount,
+ &fts->amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s'\n",
+ amount);
+ GNUNET_assert (0);
+ }
+ return fts;
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_admin_add_kycauth (
+ const char *label,
+ const char *amount,
+ const struct TALER_BANK_AuthenticationData *auth,
+ const char *payto_debit_account,
+ const char *account_ref)
+{
+ struct TALER_TESTING_Command cmd = {
+ .cls = make_fts (amount,
+ auth,
+ payto_debit_account,
+ account_ref),
+ .label = label,
+ .run = &admin_add_kycauth_run,
+ .cleanup = &admin_add_kycauth_cleanup,
+ .traits = &admin_add_kycauth_traits
+ };
+
+ return cmd;
+}
+
+
+/* end of testing_api_cmd_bank_admin_add_kycauth.c */
diff --git a/src/testing/testing_api_cmd_kyc_check_get.c b/src/testing/testing_api_cmd_kyc_check_get.c
@@ -39,6 +39,11 @@ struct KycCheckGetState
const char *payment_target_reference;
/**
+ * Command to get an account private key from.
+ */
+ const char *account_reference;
+
+ /**
* Expected HTTP response code.
*/
unsigned int expected_response_code;
@@ -114,6 +119,7 @@ check_kyc_run (void *cls,
{
struct KycCheckGetState *kcg = cls;
const struct TALER_TESTING_Command *res_cmd;
+ const struct TALER_TESTING_Command *acc_cmd;
const uint64_t *requirement_row;
const union TALER_AccountPrivateKeyP *account_priv;
@@ -128,6 +134,15 @@ check_kyc_run (void *cls,
TALER_TESTING_interpreter_fail (kcg->is);
return;
}
+ acc_cmd = TALER_TESTING_interpreter_lookup_command (
+ kcg->is,
+ kcg->account_reference);
+ if (NULL == acc_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (kcg->is);
+ return;
+ }
if (GNUNET_OK !=
TALER_TESTING_get_trait_legi_requirement_row (res_cmd,
&requirement_row))
@@ -137,7 +152,7 @@ check_kyc_run (void *cls,
return;
}
if (GNUNET_OK !=
- TALER_TESTING_get_trait_account_priv (res_cmd,
+ TALER_TESTING_get_trait_account_priv (acc_cmd,
&account_priv))
{
GNUNET_break (0);
@@ -217,12 +232,14 @@ check_kyc_traits (void *cls,
struct TALER_TESTING_Command
TALER_TESTING_cmd_check_kyc_get (const char *label,
const char *payment_target_reference,
+ const char *account_reference,
unsigned int expected_response_code)
{
struct KycCheckGetState *kcg;
kcg = GNUNET_new (struct KycCheckGetState);
kcg->payment_target_reference = payment_target_reference;
+ kcg->account_reference = account_reference;
kcg->expected_response_code = expected_response_code;
{
struct TALER_TESTING_Command cmd = {