commit f1af21e4537dd59e31d532f9495a0bd7a0020ad0
parent 914358f414ba29195ff7972e7e2875457af2d566
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 30 Oct 2025 21:39:05 +0100
fix #10541
Diffstat:
2 files changed, 146 insertions(+), 40 deletions(-)
diff --git a/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c b/src/backend/taler-merchant-httpd_private-get-instances-ID-kyc.c
@@ -685,31 +685,14 @@ ekr_expand_response (struct ExchangeKycRequest *ekr)
/**
- * We are done with the KYC request @a ekr. Remove it from the work list and
- * check if we are done overall.
+ * We are done with asynchronous processing, generate the
+ * response for the @e kc.
*
- * @param[in] ekr key request that is done (and will be freed)
+ * @param[in,out] kc KYC context to respond for
*/
static void
-ekr_finished (struct ExchangeKycRequest *ekr)
+kc_respond (struct KycContext *kc)
{
- struct KycContext *kc = ekr->kc;
-
- ekr_expand_response (ekr);
- GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
- kc->exchange_pending_tail,
- ekr);
- json_decref (ekr->jlimits);
- json_decref (ekr->pkaa);
- if (NULL != ekr->keys)
- TALER_EXCHANGE_keys_decref (ekr->keys);
- GNUNET_free (ekr->exchange_url);
- GNUNET_free (ekr->payto_uri.full_payto);
- GNUNET_free (ekr);
-
- if (NULL != kc->exchange_pending_head)
- return; /* wait for more */
-
if ( (! kc->return_immediately) &&
(! GNUNET_TIME_absolute_is_past (kc->timeout)) )
{
@@ -736,6 +719,35 @@ ekr_finished (struct ExchangeKycRequest *ekr)
/**
+ * We are done with the KYC request @a ekr. Remove it from the work list and
+ * check if we are done overall.
+ *
+ * @param[in] ekr key request that is done (and will be freed)
+ */
+static void
+ekr_finished (struct ExchangeKycRequest *ekr)
+{
+ struct KycContext *kc = ekr->kc;
+
+ ekr_expand_response (ekr);
+ GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
+ kc->exchange_pending_tail,
+ ekr);
+ json_decref (ekr->jlimits);
+ json_decref (ekr->pkaa);
+ if (NULL != ekr->keys)
+ TALER_EXCHANGE_keys_decref (ekr->keys);
+ GNUNET_free (ekr->exchange_url);
+ GNUNET_free (ekr->payto_uri.full_payto);
+ GNUNET_free (ekr);
+
+ if (NULL != kc->exchange_pending_head)
+ return; /* wait for more */
+ kc_respond (kc);
+}
+
+
+/**
* Figure out which exchange accounts from @a keys could
* be used for a KYC auth wire transfer from the account
* that @a ekr is checking. Will set the "pkaa" array
@@ -879,6 +891,72 @@ kyc_with_exchange (void *cls,
/**
+ * Closure for add_unreachable_status().
+ */
+struct UnreachableContext
+{
+ /**
+ * Where we are building the response.
+ */
+ struct KycContext *kc;
+
+ /**
+ * Pointer to our account hash.
+ */
+ const struct TALER_MerchantWireHashP *h_wire;
+
+ /**
+ * Bank account for which we have no status from any exchange.
+ */
+ struct TALER_FullPayto payto_uri;
+
+};
+
+/**
+ * Add all trusted exchanges with "unknown" status for the
+ * bank account given in the context.
+ *
+ * @param cls a `struct UnreachableContext`
+ * @param url base URL of the exchange
+ * @param exchange internal handle for the exchange
+ */
+static void
+add_unreachable_status (void *cls,
+ const char *url,
+ const struct TMH_Exchange *exchange)
+{
+ struct UnreachableContext *uc = cls;
+ struct KycContext *kc = uc->kc;
+
+ GNUNET_assert (
+ 0 ==
+ json_array_append_new (
+ kc->kycs_data,
+ GNUNET_JSON_PACK (
+ TALER_JSON_pack_full_payto (
+ "payto_uri",
+ uc->payto_uri),
+ GNUNET_JSON_pack_data_auto (
+ "h_wire",
+ uc->h_wire),
+ GNUNET_JSON_pack_string (
+ "status",
+ "exchange-unreachable"),
+ GNUNET_JSON_pack_string (
+ "exchange_url",
+ url),
+ GNUNET_JSON_pack_bool ("no_keys",
+ true),
+ GNUNET_JSON_pack_bool ("auth_conflict",
+ false),
+ GNUNET_JSON_pack_uint64 ("exchange_http_status",
+ 0)
+ )));
+
+}
+
+
+/**
* Function called from account_kyc_get_status() with KYC status information
* for this merchant.
*
@@ -911,6 +989,21 @@ kyc_status_cb (
struct KycContext *kc = cls;
struct ExchangeKycRequest *ekr;
+ if (NULL == exchange_url)
+ {
+ struct UnreachableContext uc = {
+ .kc = kc,
+ .h_wire = h_wire,
+ .payto_uri = payto_uri
+ };
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Account has unknown KYC status for all exchanges.\n");
+ TMH_exchange_get_trusted (&add_unreachable_status,
+ &uc);
+ kc_respond (kc);
+ return;
+ }
if (! TMH_EXCHANGES_check_trusted (exchange_url))
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
diff --git a/src/backenddb/pg_account_kyc_get_status.c b/src/backenddb/pg_account_kyc_get_status.c
@@ -73,37 +73,50 @@ kyc_status_cb (void *cls,
for (unsigned int i = 0; i < num_results; i++)
{
struct TALER_MerchantWireHashP h_wire;
- char *exchange_url;
+ char *exchange_url = NULL;
struct TALER_FullPayto payto_uri;
struct GNUNET_TIME_Timestamp last_check;
- bool kyc_ok;
+ bool kyc_ok = false;
struct TALER_AccountAccessTokenP access_token;
- bool no_auth;
- uint32_t h32;
- uint32_t e32;
- bool in_aml_review;
+ bool no_auth = false;
+ uint32_t h32 = 0;
+ uint32_t e32 = 0;
+ bool in_aml_review = false;
+ bool no_mk; /* left join on merchant_kyc table yielded nothing */
json_t *jlimits = NULL;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("h_wire",
&h_wire),
GNUNET_PQ_result_spec_string ("payto_uri",
&payto_uri.full_payto),
- GNUNET_PQ_result_spec_string ("exchange_url",
- &exchange_url),
- GNUNET_PQ_result_spec_timestamp ("kyc_timestamp",
- &last_check),
- GNUNET_PQ_result_spec_bool ("kyc_ok",
- &kyc_ok),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("exchange_url",
+ &exchange_url),
+ &no_mk),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_timestamp ("kyc_timestamp",
+ &last_check),
+ &no_mk),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_bool ("kyc_ok",
+ &kyc_ok),
+ &no_mk),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("access_token",
&access_token),
&no_auth),
- GNUNET_PQ_result_spec_uint32 ("exchange_http_status",
- &h32),
- GNUNET_PQ_result_spec_uint32 ("exchange_ec_code",
- &e32),
- GNUNET_PQ_result_spec_bool ("aml_review",
- &in_aml_review),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_uint32 ("exchange_http_status",
+ &h32),
+ &no_mk),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_uint32 ("exchange_ec_code",
+ &e32),
+ &no_mk),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_bool ("aml_review",
+ &in_aml_review),
+ &no_mk),
GNUNET_PQ_result_spec_allow_null (
TALER_PQ_result_spec_json ("jaccount_limits",
&jlimits),
@@ -186,7 +199,7 @@ TMH_PG_account_kyc_get_status (
" FROM merchant_instances mi"
" JOIN merchant_accounts ma"
" USING (merchant_serial)"
- " JOIN merchant_kyc mk"
+ " LEFT JOIN merchant_kyc mk"
" USING (account_serial)"
" WHERE (mi.merchant_id=$1)"
" AND ma.active"