exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

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:
Msrc/include/taler_testing_lib.h | 28++++++++++++++++++++++++++--
Msrc/kyclogic/kyclogic_api.c | 2+-
Msrc/testing/Makefile.am | 1+
Msrc/testing/testing_api_cmd_bank_admin_add_incoming.c | 40+++++++++++++---------------------------
Asrc/testing/testing_api_cmd_bank_admin_add_kycauth.c | 364+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/testing/testing_api_cmd_kyc_check_get.c | 19++++++++++++++++++-
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 = {