/*
This file is part of TALER
Copyright (C) 2021 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
*/
/**
* @file testing_api_cmd_kyc_get.c
* @brief command to test kyc_get request
* @author Christian Grothoff
*/
#include "platform.h"
#include
#include
#include "taler_merchant_service.h"
#include "taler_merchant_testing_lib.h"
/**
* State for a "/kyc" GET CMD.
*/
struct KycGetState
{
/**
* Operation handle for a GET /private/kyc GET request.
*/
struct TALER_MERCHANT_KycGetHandle *kgh;
/**
* Base URL of the merchant serving the request.
*/
const char *merchant_url;
/**
* Instance to query, NULL if part of @e merchant_url
*/
const char *instance_id;
/**
* Reference to command providing wire hash, NULL to
* query all accounts.
*/
const char *h_wire_ref;
/**
* URL of exchange to query.
*/
const char *exchange_url;
/**
* Set to the payto hash of the first account
* for which we failed to pass the KYC check.
*/
struct TALER_PaytoHashP h_payto;
/**
* Expected HTTP response code.
*/
unsigned int expected_http_status;
/**
* Expected AML state.
*/
enum TALER_AmlDecisionState expected_aml_state;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
};
/**
* Free the state of a "/kyc" GET CMD, and
* possibly cancel a pending "kyc" GET operation.
*
* @param cls closure with the `struct KycGetState`
* @param cmd command currently being freed.
*/
static void
kyc_get_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct KycGetState *cs = cls;
if (NULL != cs->kgh)
{
TALER_LOG_WARNING ("/kyc GET operation did not complete\n");
TALER_MERCHANT_kyc_get_cancel (cs->kgh);
}
GNUNET_free (cs);
}
/**
* Process "GET /public/kyc_get" (lookup) response.
*
* @param cls closure
* @param kr response we got
*/
static void
kyc_get_cb (void *cls,
const struct TALER_MERCHANT_KycResponse *kr)
{
struct KycGetState *cs = cls;
cs->kgh = NULL;
if (kr->hr.http_status != cs->expected_http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Expected status %u, got %u\n",
cs->expected_http_status,
kr->hr.http_status);
TALER_TESTING_FAIL (cs->is);
}
switch (kr->hr.http_status)
{
case MHD_HTTP_ACCEPTED:
if ( ( (TALER_AML_NORMAL != cs->expected_aml_state) &&
(0 == kr->details.kyc_status.pending_kycs_length) ) ||
( (0 < kr->details.kyc_status.pending_kycs_length) &&
(cs->expected_aml_state !=
kr->details.kyc_status.pending_kycs[0].aml_status) ) )
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Expected AML state %u, got %u/%u\n",
cs->expected_aml_state,
kr->details.kyc_status.pending_kycs[0].aml_status,
kr->details.kyc_status.pending_kycs_length);
TALER_TESTING_FAIL (cs->is);
}
for (unsigned int i = 0; idetails.kyc_status.pending_kycs_length; i++)
{
const char *url;
const char *tok;
const char *end;
char *dec;
const char *eq;
const char *nq;
size_t toklen;
url = kr->details.kyc_status.pending_kycs[i].kyc_url;
if (NULL == url)
{
/* AML status here must be either pending or frozne */
switch (kr->details.kyc_status.pending_kycs[i].aml_status)
{
case TALER_AML_NORMAL:
TALER_TESTING_FAIL (cs->is);
case TALER_AML_PENDING:
continue;
case TALER_AML_FROZEN:
continue;
}
TALER_TESTING_FAIL (cs->is);
}
tok = strstr (url, "&redirect_uri=");
if (NULL == tok)
TALER_TESTING_FAIL (cs->is);
tok += strlen ("&redirect_uri=");
end = strchr (tok, '&');
if (NULL == end)
toklen = strlen (tok);
else
toklen = end - tok;
(void) GNUNET_STRINGS_urldecode (tok,
toklen,
&dec);
eq = strstr (dec, "/kyc-proof/");
if (NULL == eq)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Received unexpected KYC URL `%s' (%s)\n",
url,
dec);
GNUNET_free (dec);
TALER_TESTING_FAIL (cs->is);
}
GNUNET_free (dec);
eq = strstr (url, "&state=");
if (NULL == eq)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Received unexpected 'state'-less KYC URL `%s' (%s)\n",
url,
dec);
TALER_TESTING_FAIL (cs->is);
}
eq += strlen ("&state=");
nq = strchr (eq, '&');
if (NULL == nq)
nq = eq + strlen (eq);
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (eq,
nq - eq,
&cs->h_payto,
sizeof (cs->h_payto)))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Received unexpected KYC URL `%s' (%s) - no h_payto in state\n",
url,
eq);
TALER_TESTING_FAIL (cs->is);
}
}
break;
}
TALER_TESTING_interpreter_next (cs->is);
}
/**
* Run the "kyc_get" CMD.
*
* @param cls closure.
* @param cmd command being currently run.
* @param is interpreter state.
*/
static void
kyc_get_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct KycGetState *cs = cls;
const struct TALER_MerchantWireHashP *h_wire = NULL;
cs->is = is;
if (NULL != cs->h_wire_ref)
{
const struct TALER_TESTING_Command *wire_cmd;
if (NULL ==
(wire_cmd =
TALER_TESTING_interpreter_lookup_command (cs->is,
cs->h_wire_ref)))
{
GNUNET_break (0);
TALER_TESTING_FAIL (cs->is);
}
/* Note: at the time of writing, no command offers an h_wire trait,
so for now this code is dead and 'h_wire_ref' must always be NULL... */
if (GNUNET_OK !=
TALER_TESTING_get_trait_h_wire (wire_cmd,
&h_wire))
{
GNUNET_break (0);
TALER_TESTING_FAIL (cs->is);
}
}
if (NULL == cs->instance_id)
cs->kgh = TALER_MERCHANT_kyc_get (TALER_TESTING_interpreter_get_context (
is),
cs->merchant_url,
h_wire,
cs->exchange_url,
GNUNET_TIME_UNIT_ZERO,
&kyc_get_cb,
cs);
else
cs->kgh = TALER_MERCHANT_management_kyc_get (
TALER_TESTING_interpreter_get_context (is),
cs->merchant_url,
cs->instance_id,
h_wire,
cs->exchange_url,
GNUNET_TIME_UNIT_ZERO,
&kyc_get_cb,
cs);
GNUNET_assert (NULL != cs->kgh);
}
/**
* Offer internal data from "KYC" GET CMD.
*
* @param cls closure.
* @param[out] ret result (could be anything).
* @param trait name of the trait.
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
static enum GNUNET_GenericReturnValue
kyc_get_traits (void *cls,
const void **ret,
const char *trait,
unsigned int index)
{
struct KycGetState *cs = cls;
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_h_payto (
&cs->h_payto),
TALER_TESTING_trait_end ()
};
return TALER_TESTING_get_trait (traits,
ret,
trait,
index);
}
struct TALER_TESTING_Command
TALER_TESTING_cmd_merchant_kyc_get (
const char *label,
const char *merchant_url,
const char *instance_id,
const char *h_wire_ref,
const char *exchange_url,
unsigned int expected_http_status,
enum TALER_AmlDecisionState expected_aml_state)
{
struct KycGetState *cs;
cs = GNUNET_new (struct KycGetState);
cs->merchant_url = merchant_url;
cs->instance_id = instance_id;
cs->h_wire_ref = h_wire_ref;
cs->exchange_url = exchange_url;
cs->expected_http_status = expected_http_status;
cs->expected_aml_state = expected_aml_state;
{
struct TALER_TESTING_Command cmd = {
.cls = cs,
.label = label,
.run = &kyc_get_run,
.cleanup = &kyc_get_cleanup,
.traits = &kyc_get_traits
};
return cmd;
}
}
/* end of testing_api_cmd_kyc_get.c */