LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_private-get-instances-ID-kyc.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 65.9 % 361 238
Test Date: 2025-10-31 14:20:14 Functions: 82.4 % 17 14

            Line data    Source code
       1              : /*
       2              :   This file is part of GNU Taler
       3              :   (C) 2021-2024 Taler Systems SA
       4              : 
       5              :   GNU Taler is free software; you can redistribute it and/or modify
       6              :   it under the terms of the GNU Affero General Public License as
       7              :   published by the Free Software Foundation; either version 3,
       8              :   or (at your option) any later version.
       9              : 
      10              :   GNU Taler is distributed in the hope that it will be useful, but
      11              :   WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13              :   GNU General Public License for more details.
      14              : 
      15              :   You should have received a copy of the GNU General Public
      16              :   License along with TALER; see the file COPYING.  If not,
      17              :   see <http://www.gnu.org/licenses/>
      18              : */
      19              : 
      20              : /**
      21              :  * @file taler-merchant-httpd_private-get-instances-ID-kyc.c
      22              :  * @brief implementing GET /instances/$ID/kyc request handling
      23              :  * @author Christian Grothoff
      24              :  */
      25              : #include "platform.h"
      26              : #include "taler-merchant-httpd_private-get-instances-ID-kyc.h"
      27              : #include "taler-merchant-httpd_helper.h"
      28              : #include "taler-merchant-httpd_exchanges.h"
      29              : #include <taler/taler_json_lib.h>
      30              : #include <taler/taler_dbevents.h>
      31              : #include <regex.h>
      32              : 
      33              : /**
      34              :  * Information we keep per /kyc request.
      35              :  */
      36              : struct KycContext;
      37              : 
      38              : 
      39              : /**
      40              :  * Structure for tracking requests to the exchange's
      41              :  * ``/kyc-check`` API.
      42              :  */
      43              : struct ExchangeKycRequest
      44              : {
      45              :   /**
      46              :    * Kept in a DLL.
      47              :    */
      48              :   struct ExchangeKycRequest *next;
      49              : 
      50              :   /**
      51              :    * Kept in a DLL.
      52              :    */
      53              :   struct ExchangeKycRequest *prev;
      54              : 
      55              :   /**
      56              :    * Find operation where we connect to the respective exchange.
      57              :    */
      58              :   struct TMH_EXCHANGES_KeysOperation *fo;
      59              : 
      60              :   /**
      61              :    * JSON array of payto-URIs with KYC auth wire transfer
      62              :    * instructions.  Provided if @e auth_ok is false and
      63              :    * @e kyc_auth_conflict is false.
      64              :    */
      65              :   json_t *pkaa;
      66              : 
      67              :   /**
      68              :    * The keys of the exchange.
      69              :    */
      70              :   struct TALER_EXCHANGE_Keys *keys;
      71              : 
      72              :   /**
      73              :    * KYC request this exchange request is made for.
      74              :    */
      75              :   struct KycContext *kc;
      76              : 
      77              :   /**
      78              :    * JSON array of AccountLimits that apply, NULL if
      79              :    * unknown (and likely defaults apply).
      80              :    */
      81              :   json_t *jlimits;
      82              : 
      83              :   /**
      84              :    * Our account's payto URI.
      85              :    */
      86              :   struct TALER_FullPayto payto_uri;
      87              : 
      88              :   /**
      89              :    * Base URL of the exchange.
      90              :    */
      91              :   char *exchange_url;
      92              : 
      93              :   /**
      94              :    * Hash of the wire account (with salt) we are checking.
      95              :    */
      96              :   struct TALER_MerchantWireHashP h_wire;
      97              : 
      98              :   /**
      99              :    * Current access token for the KYC SPA. Only set
     100              :    * if @e auth_ok is true.
     101              :    */
     102              :   struct TALER_AccountAccessTokenP access_token;
     103              : 
     104              :   /**
     105              :    * Timestamp when we last got a reply from the exchange.
     106              :    */
     107              :   struct GNUNET_TIME_Timestamp last_check;
     108              : 
     109              :   /**
     110              :    * Last HTTP status code obtained via /kyc-check from
     111              :    * the exchange.
     112              :    */
     113              :   unsigned int last_http_status;
     114              : 
     115              :   /**
     116              :    * Last Taler error code returned from /kyc-check.
     117              :    */
     118              :   enum TALER_ErrorCode last_ec;
     119              : 
     120              :   /**
     121              :    * True if this account
     122              :    * cannot work at this exchange because KYC auth is
     123              :    * impossible.
     124              :    */
     125              :   bool kyc_auth_conflict;
     126              : 
     127              :   /**
     128              :    * We could not get /keys from the exchange.
     129              :    */
     130              :   bool no_keys;
     131              : 
     132              :   /**
     133              :    * True if @e access_token is available.
     134              :    */
     135              :   bool auth_ok;
     136              : 
     137              :   /**
     138              :    * True if we believe no KYC is currently required
     139              :    * for this account at this exchange.
     140              :    */
     141              :   bool kyc_ok;
     142              : 
     143              :   /**
     144              :    * True if the exchange exposed to us that the account
     145              :    * is currently under AML review.
     146              :    */
     147              :   bool in_aml_review;
     148              : 
     149              : 
     150              : };
     151              : 
     152              : 
     153              : /**
     154              :  * Information we keep per /kyc request.
     155              :  */
     156              : struct KycContext
     157              : {
     158              :   /**
     159              :    * Stored in a DLL.
     160              :    */
     161              :   struct KycContext *next;
     162              : 
     163              :   /**
     164              :    * Stored in a DLL.
     165              :    */
     166              :   struct KycContext *prev;
     167              : 
     168              :   /**
     169              :    * Connection we are handling.
     170              :    */
     171              :   struct MHD_Connection *connection;
     172              : 
     173              :   /**
     174              :    * Instance we are serving.
     175              :    */
     176              :   struct TMH_MerchantInstance *mi;
     177              : 
     178              :   /**
     179              :    * Our handler context.
     180              :    */
     181              :   struct TMH_HandlerContext *hc;
     182              : 
     183              :   /**
     184              :    * Response to return, NULL if we don't have one yet.
     185              :    */
     186              :   struct MHD_Response *response;
     187              : 
     188              :   /**
     189              :    * JSON array where we are building up the array with
     190              :    * pending KYC operations.
     191              :    */
     192              :   json_t *kycs_data;
     193              : 
     194              :   /**
     195              :    * Head of DLL of requests we are making to an
     196              :    * exchange to inquire about the latest KYC status.
     197              :    */
     198              :   struct ExchangeKycRequest *exchange_pending_head;
     199              : 
     200              :   /**
     201              :    * Tail of DLL of requests we are making to an
     202              :    * exchange to inquire about the latest KYC status.
     203              :    */
     204              :   struct ExchangeKycRequest *exchange_pending_tail;
     205              : 
     206              :   /**
     207              :    * Set to the exchange URL, or NULL to not filter by
     208              :    * exchange.
     209              :    */
     210              :   const char *exchange_url;
     211              : 
     212              :   /**
     213              :    * Notification handler from database on changes
     214              :    * to the KYC status.
     215              :    */
     216              :   struct GNUNET_DB_EventHandler *eh;
     217              : 
     218              :   /**
     219              :    * Set to the h_wire of the merchant account if
     220              :    * @a have_h_wire is true, used to filter by account.
     221              :    */
     222              :   struct TALER_MerchantWireHashP h_wire;
     223              : 
     224              :   /**
     225              :    * How long are we willing to wait for the exchange(s)?
     226              :    */
     227              :   struct GNUNET_TIME_Absolute timeout;
     228              : 
     229              :   /**
     230              :    * HTTP status code to use for the reply, i.e 200 for "OK".
     231              :    * Special value UINT_MAX is used to indicate hard errors
     232              :    * (no reply, return #MHD_NO).
     233              :    */
     234              :   unsigned int response_code;
     235              : 
     236              :   /**
     237              :    * #GNUNET_NO if the @e connection was not suspended,
     238              :    * #GNUNET_YES if the @e connection was suspended,
     239              :    * #GNUNET_SYSERR if @e connection was resumed to as
     240              :    * part of #MH_force_pc_resume during shutdown.
     241              :    */
     242              :   enum GNUNET_GenericReturnValue suspended;
     243              : 
     244              :   /**
     245              :    * What state are we long-polling for?
     246              :    */
     247              :   enum TALER_EXCHANGE_KycLongPollTarget lpt;
     248              : 
     249              :   /**
     250              :    * True if @e h_wire was given.
     251              :    */
     252              :   bool have_h_wire;
     253              : 
     254              :   /**
     255              :    * We're still waiting on the exchange to determine
     256              :    * the KYC status of our deposit(s).
     257              :    */
     258              :   bool return_immediately;
     259              : 
     260              : };
     261              : 
     262              : 
     263              : /**
     264              :  * Head of DLL.
     265              :  */
     266              : static struct KycContext *kc_head;
     267              : 
     268              : /**
     269              :  * Tail of DLL.
     270              :  */
     271              : static struct KycContext *kc_tail;
     272              : 
     273              : 
     274              : void
     275           15 : TMH_force_kyc_resume ()
     276              : {
     277           15 :   for (struct KycContext *kc = kc_head;
     278           15 :        NULL != kc;
     279            0 :        kc = kc->next)
     280              :   {
     281            0 :     if (GNUNET_YES == kc->suspended)
     282              :     {
     283            0 :       kc->suspended = GNUNET_SYSERR;
     284            0 :       MHD_resume_connection (kc->connection);
     285              :     }
     286              :   }
     287           15 : }
     288              : 
     289              : 
     290              : /**
     291              :  * Custom cleanup routine for a `struct KycContext`.
     292              :  *
     293              :  * @param cls the `struct KycContext` to clean up.
     294              :  */
     295              : static void
     296            9 : kyc_context_cleanup (void *cls)
     297              : {
     298            9 :   struct KycContext *kc = cls;
     299              :   struct ExchangeKycRequest *ekr;
     300              : 
     301            9 :   while (NULL != (ekr = kc->exchange_pending_head))
     302              :   {
     303            0 :     GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
     304              :                                  kc->exchange_pending_tail,
     305              :                                  ekr);
     306            0 :     if (NULL != ekr->fo)
     307              :     {
     308            0 :       TMH_EXCHANGES_keys4exchange_cancel (ekr->fo);
     309            0 :       ekr->fo = NULL;
     310              :     }
     311            0 :     json_decref (ekr->pkaa);
     312            0 :     json_decref (ekr->jlimits);
     313            0 :     if (NULL != ekr->keys)
     314            0 :       TALER_EXCHANGE_keys_decref (ekr->keys);
     315            0 :     GNUNET_free (ekr->exchange_url);
     316            0 :     GNUNET_free (ekr->payto_uri.full_payto);
     317            0 :     GNUNET_free (ekr);
     318              :   }
     319            9 :   if (NULL != kc->eh)
     320              :   {
     321            4 :     TMH_db->event_listen_cancel (kc->eh);
     322            4 :     kc->eh = NULL;
     323              :   }
     324            9 :   if (NULL != kc->response)
     325              :   {
     326            7 :     MHD_destroy_response (kc->response);
     327            7 :     kc->response = NULL;
     328              :   }
     329            9 :   GNUNET_CONTAINER_DLL_remove (kc_head,
     330              :                                kc_tail,
     331              :                                kc);
     332            9 :   json_decref (kc->kycs_data);
     333            9 :   GNUNET_free (kc);
     334            9 : }
     335              : 
     336              : 
     337              : /**
     338              :  * Resume the given KYC context and send the final response.  Stores the
     339              :  * response in the @a kc and signals MHD to resume the connection.  Also
     340              :  * ensures MHD runs immediately.
     341              :  *
     342              :  * @param kc KYC context
     343              :  */
     344              : static void
     345            7 : resume_kyc_with_response (struct KycContext *kc)
     346              : {
     347            7 :   kc->response_code = MHD_HTTP_OK;
     348            7 :   kc->response = TALER_MHD_MAKE_JSON_PACK (
     349              :     GNUNET_JSON_pack_array_incref ("kyc_data",
     350              :                                    kc->kycs_data));
     351            7 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     352              :               "Resuming /kyc handling as exchange interaction is done (%u)\n",
     353              :               MHD_HTTP_OK);
     354            7 :   if (GNUNET_YES == kc->suspended)
     355              :   {
     356            3 :     kc->suspended = GNUNET_NO;
     357            3 :     MHD_resume_connection (kc->connection);
     358            3 :     TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
     359              :   }
     360            7 : }
     361              : 
     362              : 
     363              : /**
     364              :  * Handle a DB event about an update relevant
     365              :  * for the processing of the kyc request.
     366              :  *
     367              :  * @param cls our `struct KycContext`
     368              :  * @param extra additional event data provided
     369              :  * @param extra_size number of bytes in @a extra
     370              :  */
     371              : static void
     372            1 : kyc_change_cb (void *cls,
     373              :                const void *extra,
     374              :                size_t extra_size)
     375              : {
     376            1 :   struct KycContext *kc = cls;
     377              : 
     378            1 :   if (GNUNET_YES == kc->suspended)
     379              :   {
     380            1 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     381              :                 "Resuming KYC with gateway timeout\n");
     382            1 :     kc->suspended = GNUNET_NO;
     383            1 :     MHD_resume_connection (kc->connection);
     384            1 :     TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
     385              :   }
     386            1 : }
     387              : 
     388              : 
     389              : /**
     390              :  * Pack the given @a limit into the JSON @a limits array.
     391              :  *
     392              :  * @param limit account limit to pack
     393              :  * @param[in,out] limits JSON array to extend
     394              :  */
     395              : static void
     396            0 : pack_limit (const struct TALER_EXCHANGE_AccountLimit *limit,
     397              :             json_t *limits)
     398              : {
     399              :   json_t *jl;
     400              : 
     401            0 :   jl = GNUNET_JSON_PACK (
     402              :     TALER_JSON_pack_kycte ("operation_type",
     403              :                            limit->operation_type),
     404              :     GNUNET_JSON_pack_time_rel ("timeframe",
     405              :                                limit->timeframe),
     406              :     TALER_JSON_pack_amount ("threshold",
     407              :                             &limit->threshold),
     408              :     GNUNET_JSON_pack_bool ("soft_limit",
     409              :                            limit->soft_limit)
     410              :     );
     411            0 :   GNUNET_assert (0 ==
     412              :                  json_array_append_new (limits,
     413              :                                         jl));
     414            0 : }
     415              : 
     416              : 
     417              : /**
     418              :  * Return JSON array with AccountLimit objects giving
     419              :  * the current limits for this exchange.
     420              :  *
     421              :  * @param[in,out] ekr overall request context
     422              :  */
     423              : static json_t *
     424            9 : get_exchange_limits (
     425              :   struct ExchangeKycRequest *ekr)
     426              : {
     427            9 :   const struct TALER_EXCHANGE_Keys *keys = ekr->keys;
     428              :   json_t *limits;
     429              : 
     430            9 :   if (NULL != ekr->jlimits)
     431              :   {
     432            4 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     433              :                 "Returning custom KYC limits\n");
     434            4 :     return json_incref (ekr->jlimits);
     435              :   }
     436            5 :   if (NULL == keys)
     437              :   {
     438            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     439              :                 "No keys, thus no default KYC limits known\n");
     440            0 :     return NULL;
     441              :   }
     442            5 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     443              :               "Returning default KYC limits (%u/%u)\n",
     444              :               keys->hard_limits_length,
     445              :               keys->zero_limits_length);
     446            5 :   limits = json_array ();
     447            5 :   GNUNET_assert (NULL != limits);
     448            5 :   for (unsigned int i = 0; i<keys->hard_limits_length; i++)
     449              :   {
     450            0 :     const struct TALER_EXCHANGE_AccountLimit *limit
     451            0 :       = &keys->hard_limits[i];
     452              : 
     453            0 :     pack_limit (limit,
     454              :                 limits);
     455              :   }
     456            7 :   for (unsigned int i = 0; i<keys->zero_limits_length; i++)
     457              :   {
     458            2 :     const struct TALER_EXCHANGE_ZeroLimitedOperation *zlimit
     459            2 :       = &keys->zero_limits[i];
     460              :     json_t *jl;
     461              :     struct TALER_Amount zero;
     462              : 
     463            2 :     GNUNET_assert (GNUNET_OK ==
     464              :                    TALER_amount_set_zero (keys->currency,
     465              :                                           &zero));
     466            2 :     jl = GNUNET_JSON_PACK (
     467              :       TALER_JSON_pack_kycte ("operation_type",
     468              :                              zlimit->operation_type),
     469              :       GNUNET_JSON_pack_time_rel ("timeframe",
     470              :                                  GNUNET_TIME_UNIT_ZERO),
     471              :       TALER_JSON_pack_amount ("threshold",
     472              :                               &zero),
     473              :       GNUNET_JSON_pack_bool ("soft_limit",
     474              :                              true)
     475              :       );
     476            2 :     GNUNET_assert (0 ==
     477              :                    json_array_append_new (limits,
     478              :                                           jl));
     479              :   }
     480            5 :   return limits;
     481              : }
     482              : 
     483              : 
     484              : /**
     485              :  * Maps @a ekr to a status code for clients to interpret the
     486              :  * overall result.
     487              :  *
     488              :  * @param ekr request summary
     489              :  * @return status of the KYC state as a string
     490              :  */
     491              : static const char *
     492            9 : map_to_status (const struct ExchangeKycRequest *ekr)
     493              : {
     494            9 :   if (ekr->no_keys)
     495              :   {
     496            0 :     return "no-exchange-keys";
     497              :   }
     498            9 :   if (ekr->kyc_ok)
     499              :   {
     500            7 :     if (NULL != ekr->jlimits)
     501              :     {
     502              :       size_t off;
     503              :       json_t *limit;
     504            4 :       json_array_foreach (ekr->jlimits, off, limit)
     505              :       {
     506              :         struct TALER_Amount threshold;
     507              :         enum TALER_KYCLOGIC_KycTriggerEvent operation_type;
     508            4 :         bool soft = false;
     509              :         struct GNUNET_JSON_Specification spec[] = {
     510            4 :           TALER_JSON_spec_kycte ("operation_type",
     511              :                                  &operation_type),
     512            4 :           TALER_JSON_spec_amount_any ("threshold",
     513              :                                       &threshold),
     514            4 :           GNUNET_JSON_spec_mark_optional (
     515              :             GNUNET_JSON_spec_bool ("soft_limit",
     516              :                                    &soft),
     517              :             NULL),
     518            4 :           GNUNET_JSON_spec_end ()
     519              :         };
     520              : 
     521            4 :         if (GNUNET_OK !=
     522            4 :             GNUNET_JSON_parse (limit,
     523              :                                spec,
     524              :                                NULL, NULL))
     525              :         {
     526            0 :           GNUNET_break (0);
     527            4 :           return "merchant-internal-error";
     528              :         }
     529            4 :         if (! TALER_amount_is_zero (&threshold))
     530            0 :           continue; /* only care about zero-limits */
     531            4 :         if (! soft)
     532            0 :           continue; /* only care about soft limits */
     533            4 :         if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
     534            4 :              (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) ||
     535            0 :              (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) )
     536              :         {
     537            4 :           if (! ekr->auth_ok)
     538              :           {
     539            0 :             if (ekr->kyc_auth_conflict)
     540            0 :               return "kyc-wire-impossible";
     541            0 :             return "kyc-wire-required";
     542              :           }
     543            4 :           return "kyc-required";
     544              :         }
     545              :       }
     546              :     }
     547            3 :     if (NULL == ekr->jlimits)
     548              :     {
     549              :       /* check default limits */
     550            3 :       const struct TALER_EXCHANGE_Keys *keys = ekr->keys;
     551              : 
     552            3 :       for (unsigned int i = 0; i < keys->zero_limits_length; i++)
     553              :       {
     554            0 :         enum TALER_KYCLOGIC_KycTriggerEvent operation_type
     555            0 :           = keys->zero_limits[i].operation_type;
     556              : 
     557            0 :         if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
     558            0 :              (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) ||
     559              :              (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) )
     560              :         {
     561            0 :           if (! ekr->auth_ok)
     562              :           {
     563            0 :             if (ekr->kyc_auth_conflict)
     564            0 :               return "kyc-wire-impossible";
     565            0 :             return "kyc-wire-required";
     566              :           }
     567            0 :           return "kyc-required";
     568              :         }
     569              :       }
     570              :     }
     571            3 :     return "ready";
     572              :   }
     573            2 :   if (! ekr->auth_ok)
     574              :   {
     575            2 :     if (ekr->kyc_auth_conflict)
     576            0 :       return "kyc-wire-impossible";
     577            2 :     return "kyc-wire-required";
     578              :   }
     579            0 :   if (ekr->in_aml_review)
     580            0 :     return "awaiting-aml-review";
     581            0 :   switch (ekr->last_http_status)
     582              :   {
     583            0 :   case 0:
     584            0 :     return "exchange-unreachable";
     585            0 :   case MHD_HTTP_OK:
     586              :     /* then we should have kyc_ok */
     587            0 :     GNUNET_break (0);
     588            0 :     return NULL;
     589            0 :   case MHD_HTTP_ACCEPTED:
     590              :     /* Then KYC is really what  is needed */
     591            0 :     return "kyc-required";
     592            0 :   case MHD_HTTP_NO_CONTENT:
     593              :     /* then we should have had kyc_ok! */
     594            0 :     GNUNET_break (0);
     595            0 :     return NULL;
     596            0 :   case MHD_HTTP_FORBIDDEN:
     597              :     /* then we should have had ! auth_ok */
     598            0 :     GNUNET_break (0);
     599            0 :     return NULL;
     600            0 :   case MHD_HTTP_NOT_FOUND:
     601              :     /* then we should have had ! auth_ok */
     602            0 :     GNUNET_break (0);
     603            0 :     return NULL;
     604            0 :   case MHD_HTTP_CONFLICT:
     605              :     /* then we should have had ! auth_ok */
     606            0 :     GNUNET_break (0);
     607            0 :     return NULL;
     608            0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     609            0 :     return "exchange-internal-error";
     610            0 :   case MHD_HTTP_GATEWAY_TIMEOUT:
     611            0 :     return "exchange-gateway-timeout";
     612            0 :   default:
     613            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     614              :                 "Exchange responded with unexpected HTTP status %u to /kyc-check request!\n",
     615              :                 ekr->last_http_status);
     616            0 :     break;
     617              :   }
     618            0 :   return "exchange-status-invalid";
     619              : }
     620              : 
     621              : 
     622              : /**
     623              :  * Take data from @a ekr to expand our response.
     624              :  *
     625              :  * @param ekr exchange we are done inspecting
     626              :  */
     627              : static void
     628            9 : ekr_expand_response (struct ExchangeKycRequest *ekr)
     629              : {
     630              :   const char *status;
     631              : 
     632            9 :   status = map_to_status (ekr);
     633            9 :   if (NULL == status)
     634              :   {
     635            0 :     GNUNET_break (0);
     636            0 :     status = "logic-bug";
     637              :   }
     638            9 :   GNUNET_assert (
     639              :     0 ==
     640              :     json_array_append_new (
     641              :       ekr->kc->kycs_data,
     642              :       GNUNET_JSON_PACK (
     643              :         TALER_JSON_pack_full_payto (
     644              :           "payto_uri",
     645              :           ekr->payto_uri),
     646              :         GNUNET_JSON_pack_data_auto (
     647              :           "h_wire",
     648              :           &ekr->h_wire),
     649              :         GNUNET_JSON_pack_string (
     650              :           "status",
     651              :           status),
     652              :         GNUNET_JSON_pack_string (
     653              :           "exchange_url",
     654              :           ekr->exchange_url),
     655              :         GNUNET_JSON_pack_bool ("no_keys",
     656              :                                ekr->no_keys),
     657              :         GNUNET_JSON_pack_bool ("auth_conflict",
     658              :                                ekr->kyc_auth_conflict),
     659              :         GNUNET_JSON_pack_uint64 ("exchange_http_status",
     660              :                                  ekr->last_http_status),
     661              :         (TALER_EC_NONE == ekr->last_ec)
     662              :         ? GNUNET_JSON_pack_allow_null (
     663              :           GNUNET_JSON_pack_string (
     664              :             "dummy",
     665              :             NULL))
     666              :         : GNUNET_JSON_pack_uint64 ("exchange_code",
     667              :                                    ekr->last_ec),
     668              :         ekr->auth_ok
     669              :         ? GNUNET_JSON_pack_data_auto (
     670              :           "access_token",
     671              :           &ekr->access_token)
     672              :         : GNUNET_JSON_pack_allow_null (
     673              :           GNUNET_JSON_pack_string (
     674              :             "dummy",
     675              :             NULL)),
     676              :         GNUNET_JSON_pack_allow_null (
     677              :           GNUNET_JSON_pack_array_steal (
     678              :             "limits",
     679              :             get_exchange_limits (ekr))),
     680              :         GNUNET_JSON_pack_allow_null (
     681              :           GNUNET_JSON_pack_array_incref ("payto_kycauths",
     682              :                                          ekr->pkaa))
     683              :         )));
     684            9 : }
     685              : 
     686              : 
     687              : /**
     688              :  * We are done with asynchronous processing, generate the
     689              :  * response for the @e kc.
     690              :  *
     691              :  * @param[in,out] kc KYC context to respond for
     692              :  */
     693              : static void
     694            8 : kc_respond (struct KycContext *kc)
     695              : {
     696            8 :   if ( (! kc->return_immediately) &&
     697            1 :        (! GNUNET_TIME_absolute_is_past (kc->timeout)) )
     698              :   {
     699            1 :     if (GNUNET_NO == kc->suspended)
     700              :     {
     701            0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     702              :                   "Suspending: long poll target %d not reached\n",
     703              :                   kc->lpt);
     704            0 :       MHD_suspend_connection (kc->connection);
     705            0 :       kc->suspended = GNUNET_YES;
     706              :     }
     707              :     else
     708              :     {
     709            1 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     710              :                   "Remaining suspended: long poll target %d not reached\n",
     711              :                   kc->lpt);
     712              :     }
     713            1 :     return;
     714              :   }
     715              :   /* All exchange requests done, create final
     716              :      big response from cumulated replies */
     717            7 :   resume_kyc_with_response (kc);
     718              : }
     719              : 
     720              : 
     721              : /**
     722              :  * We are done with the KYC request @a ekr.  Remove it from the work list and
     723              :  * check if we are done overall.
     724              :  *
     725              :  * @param[in] ekr key request that is done (and will be freed)
     726              :  */
     727              : static void
     728            9 : ekr_finished (struct ExchangeKycRequest *ekr)
     729              : {
     730            9 :   struct KycContext *kc = ekr->kc;
     731              : 
     732            9 :   ekr_expand_response (ekr);
     733            9 :   GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
     734              :                                kc->exchange_pending_tail,
     735              :                                ekr);
     736            9 :   json_decref (ekr->jlimits);
     737            9 :   json_decref (ekr->pkaa);
     738            9 :   if (NULL != ekr->keys)
     739            5 :     TALER_EXCHANGE_keys_decref (ekr->keys);
     740            9 :   GNUNET_free (ekr->exchange_url);
     741            9 :   GNUNET_free (ekr->payto_uri.full_payto);
     742            9 :   GNUNET_free (ekr);
     743              : 
     744            9 :   if (NULL != kc->exchange_pending_head)
     745            1 :     return; /* wait for more */
     746            8 :   kc_respond (kc);
     747              : }
     748              : 
     749              : 
     750              : /**
     751              :  * Figure out which exchange accounts from @a keys could
     752              :  * be used for a KYC auth wire transfer from the account
     753              :  * that @a ekr is checking. Will set the "pkaa" array
     754              :  * in @a ekr.
     755              :  *
     756              :  * @param[in,out] ekr request we are processing
     757              :  */
     758              : static void
     759            5 : determine_eligible_accounts (
     760              :   struct ExchangeKycRequest *ekr)
     761              : {
     762            5 :   struct KycContext *kc = ekr->kc;
     763            5 :   const struct TALER_EXCHANGE_Keys *keys = ekr->keys;
     764              :   struct TALER_Amount kyc_amount;
     765              :   char *merchant_pub_str;
     766              :   struct TALER_NormalizedPayto np;
     767              : 
     768            5 :   ekr->pkaa = json_array ();
     769            5 :   GNUNET_assert (NULL != ekr->pkaa);
     770              :   {
     771              :     const struct TALER_EXCHANGE_GlobalFee *gf;
     772              : 
     773            5 :     gf = TALER_EXCHANGE_get_global_fee (keys,
     774              :                                         GNUNET_TIME_timestamp_get ());
     775            5 :     if (NULL == gf)
     776              :     {
     777            0 :       GNUNET_assert (GNUNET_OK ==
     778              :                      TALER_amount_set_zero (keys->currency,
     779              :                                             &kyc_amount));
     780              :     }
     781              :     else
     782              :     {
     783              :       /* FIXME-#9427: history fee should be globally renamed to KYC fee... */
     784            5 :       kyc_amount = gf->fees.history;
     785              :     }
     786              :   }
     787              : 
     788              :   merchant_pub_str
     789            5 :     = GNUNET_STRINGS_data_to_string_alloc (
     790            5 :         &kc->mi->merchant_pub,
     791              :         sizeof (kc->mi->merchant_pub));
     792              :   /* For all accounts of the exchange */
     793            5 :   np = TALER_payto_normalize (ekr->payto_uri);
     794           10 :   for (unsigned int i = 0; i<keys->accounts_len; i++)
     795              :   {
     796            5 :     const struct TALER_EXCHANGE_WireAccount *account
     797            5 :       = &keys->accounts[i];
     798              : 
     799              :     /* KYC auth transfers are never supported with conversion */
     800            5 :     if (NULL != account->conversion_url)
     801            0 :       continue;
     802              :     /* filter by source account by credit_restrictions */
     803            5 :     if (GNUNET_YES !=
     804            5 :         TALER_EXCHANGE_test_account_allowed (account,
     805              :                                              true, /* credit */
     806              :                                              np))
     807            0 :       continue;
     808              :     /* exchange account is allowed, add it */
     809              :     {
     810            5 :       const char *exchange_account_payto
     811              :         = account->fpayto_uri.full_payto;
     812              :       char *payto_kycauth;
     813              : 
     814            5 :       if (TALER_amount_is_zero (&kyc_amount))
     815            0 :         GNUNET_asprintf (&payto_kycauth,
     816              :                          "%s%cmessage=KYC:%s",
     817              :                          exchange_account_payto,
     818            0 :                          (NULL == strchr (exchange_account_payto,
     819              :                                           '?'))
     820              :                          ? '?'
     821              :                          : '&',
     822              :                          merchant_pub_str);
     823              :       else
     824           10 :         GNUNET_asprintf (&payto_kycauth,
     825              :                          "%s%camount=%s&message=KYC:%s",
     826              :                          exchange_account_payto,
     827            5 :                          (NULL == strchr (exchange_account_payto,
     828              :                                           '?'))
     829              :                          ? '?'
     830              :                          : '&',
     831              :                          TALER_amount2s (&kyc_amount),
     832              :                          merchant_pub_str);
     833            5 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     834              :                   "Found account %s where KYC auth is possible\n",
     835              :                   payto_kycauth);
     836            5 :       GNUNET_assert (0 ==
     837              :                      json_array_append_new (ekr->pkaa,
     838              :                                             json_string (payto_kycauth)));
     839            5 :       GNUNET_free (payto_kycauth);
     840              :     }
     841              :   }
     842            5 :   GNUNET_free (np.normalized_payto);
     843            5 :   GNUNET_free (merchant_pub_str);
     844            5 : }
     845              : 
     846              : 
     847              : /**
     848              :  * Function called with the result of a #TMH_EXCHANGES_keys4exchange()
     849              :  * operation.  Runs the KYC check against the exchange.
     850              :  *
     851              :  * @param cls closure with our `struct ExchangeKycRequest *`
     852              :  * @param keys keys of the exchange context
     853              :  * @param exchange representation of the exchange
     854              :  */
     855              : static void
     856            5 : kyc_with_exchange (void *cls,
     857              :                    struct TALER_EXCHANGE_Keys *keys,
     858              :                    struct TMH_Exchange *exchange)
     859              : {
     860            5 :   struct ExchangeKycRequest *ekr = cls;
     861              : 
     862              :   (void) exchange;
     863            5 :   ekr->fo = NULL;
     864            5 :   if (NULL == keys)
     865              :   {
     866            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     867              :                 "Failed to download `%skeys`\n",
     868              :                 ekr->exchange_url);
     869            0 :     ekr->no_keys = true;
     870            0 :     ekr_finished (ekr);
     871            0 :     return;
     872              :   }
     873            5 :   ekr->keys = TALER_EXCHANGE_keys_incref (keys);
     874            5 :   if (! ekr->auth_ok)
     875              :   {
     876            5 :     determine_eligible_accounts (ekr);
     877            5 :     if (0 == json_array_size (ekr->pkaa))
     878              :     {
     879              :       /* No KYC auth wire transfers are possible to this exchange from
     880              :          our merchant bank account, so we cannot use this account with
     881              :          this exchange if it has any KYC requirements! */
     882            0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     883              :                   "KYC auth to `%s' impossible for merchant account `%s'\n",
     884              :                   ekr->exchange_url,
     885              :                   ekr->payto_uri.full_payto);
     886            0 :       ekr->kyc_auth_conflict = true;
     887              :     }
     888              :   }
     889            5 :   ekr_finished (ekr);
     890              : }
     891              : 
     892              : 
     893              : /**
     894              :  * Closure for add_unreachable_status().
     895              :  */
     896              : struct UnreachableContext
     897              : {
     898              :   /**
     899              :    * Where we are building the response.
     900              :    */
     901              :   struct KycContext *kc;
     902              : 
     903              :   /**
     904              :    * Pointer to our account hash.
     905              :    */
     906              :   const struct TALER_MerchantWireHashP *h_wire;
     907              : 
     908              :   /**
     909              :    * Bank account for which we have no status from any exchange.
     910              :    */
     911              :   struct TALER_FullPayto payto_uri;
     912              : 
     913              : };
     914              : 
     915              : /**
     916              :  * Add all trusted exchanges with "unknown" status for the
     917              :  * bank account given in the context.
     918              :  *
     919              :  * @param cls a `struct UnreachableContext`
     920              :  * @param url base URL of the exchange
     921              :  * @param exchange internal handle for the exchange
     922              :  */
     923              : static void
     924            0 : add_unreachable_status (void *cls,
     925              :                         const char *url,
     926              :                         const struct TMH_Exchange *exchange)
     927              : {
     928            0 :   struct UnreachableContext *uc = cls;
     929            0 :   struct KycContext *kc = uc->kc;
     930              : 
     931            0 :   GNUNET_assert (
     932              :     0 ==
     933              :     json_array_append_new (
     934              :       kc->kycs_data,
     935              :       GNUNET_JSON_PACK (
     936              :         TALER_JSON_pack_full_payto (
     937              :           "payto_uri",
     938              :           uc->payto_uri),
     939              :         GNUNET_JSON_pack_data_auto (
     940              :           "h_wire",
     941              :           uc->h_wire),
     942              :         GNUNET_JSON_pack_string (
     943              :           "status",
     944              :           "exchange-unreachable"),
     945              :         GNUNET_JSON_pack_string (
     946              :           "exchange_url",
     947              :           url),
     948              :         GNUNET_JSON_pack_bool ("no_keys",
     949              :                                true),
     950              :         GNUNET_JSON_pack_bool ("auth_conflict",
     951              :                                false),
     952              :         GNUNET_JSON_pack_uint64 ("exchange_http_status",
     953              :                                  0)
     954              :         )));
     955              : 
     956            0 : }
     957              : 
     958              : 
     959              : /**
     960              :  * Function called from account_kyc_get_status() with KYC status information
     961              :  * for this merchant.
     962              :  *
     963              :  * @param cls our `struct KycContext *`
     964              :  * @param h_wire hash of the wire account
     965              :  * @param payto_uri payto:// URI of the merchant's bank account
     966              :  * @param exchange_url base URL of the exchange for which this is a status
     967              :  * @param last_check when did we last get an update on our KYC status from the exchange
     968              :  * @param kyc_ok true if we satisfied the KYC requirements
     969              :  * @param access_token access token for the KYC SPA, NULL if we cannot access it yet (need KYC auth wire transfer)
     970              :  * @param last_http_status last HTTP status from /kyc-check
     971              :  * @param last_ec last Taler error code from /kyc-check
     972              :  * @param in_aml_review true if the account is pending review
     973              :  * @param jlimits JSON array of applicable AccountLimits, or NULL if unknown (like defaults apply)
     974              :  */
     975              : static void
     976            9 : kyc_status_cb (
     977              :   void *cls,
     978              :   const struct TALER_MerchantWireHashP *h_wire,
     979              :   struct TALER_FullPayto payto_uri,
     980              :   const char *exchange_url,
     981              :   struct GNUNET_TIME_Timestamp last_check,
     982              :   bool kyc_ok,
     983              :   const struct TALER_AccountAccessTokenP *access_token,
     984              :   unsigned int last_http_status,
     985              :   enum TALER_ErrorCode last_ec,
     986              :   bool in_aml_review,
     987              :   const json_t *jlimits)
     988              : {
     989            9 :   struct KycContext *kc = cls;
     990              :   struct ExchangeKycRequest *ekr;
     991              : 
     992            9 :   if (NULL == exchange_url)
     993              :   {
     994            0 :     struct UnreachableContext uc = {
     995              :       .kc = kc,
     996              :       .h_wire = h_wire,
     997              :       .payto_uri = payto_uri
     998              :     };
     999              : 
    1000            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1001              :                 "Account has unknown KYC status for all exchanges.\n");
    1002            0 :     TMH_exchange_get_trusted (&add_unreachable_status,
    1003              :                               &uc);
    1004            0 :     kc_respond (kc);
    1005            0 :     return;
    1006              :   }
    1007            9 :   if (! TMH_EXCHANGES_check_trusted (exchange_url))
    1008              :   {
    1009            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1010              :                 "Skipping exchange `%s': not trusted\n",
    1011              :                 exchange_url);
    1012            0 :     return;
    1013              :   }
    1014            9 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1015              :               "KYC status for `%s' at `%s' is %u/%s/%s/%s\n",
    1016              :               payto_uri.full_payto,
    1017              :               exchange_url,
    1018              :               last_http_status,
    1019              :               kyc_ok ? "KYC OK" : "KYC NEEDED",
    1020              :               in_aml_review ? "IN AML REVIEW" : "NO AML REVIEW",
    1021              :               NULL == jlimits ? "DEFAULT LIMITS" : "CUSTOM LIMITS");
    1022            9 :   switch (kc->lpt)
    1023              :   {
    1024            4 :   case TALER_EXCHANGE_KLPT_NONE:
    1025            4 :     break;
    1026            4 :   case TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER:
    1027            4 :     if (NULL != access_token)
    1028            3 :       kc->return_immediately = true;
    1029            4 :     break;
    1030            0 :   case TALER_EXCHANGE_KLPT_INVESTIGATION_DONE:
    1031            0 :     if (! in_aml_review)
    1032            0 :       kc->return_immediately = true;
    1033            0 :     break;
    1034            1 :   case TALER_EXCHANGE_KLPT_KYC_OK:
    1035            1 :     if (kyc_ok)
    1036            1 :       kc->return_immediately = true;
    1037            1 :     break;
    1038              :   }
    1039            9 :   ekr = GNUNET_new (struct ExchangeKycRequest);
    1040            9 :   GNUNET_CONTAINER_DLL_insert (kc->exchange_pending_head,
    1041              :                                kc->exchange_pending_tail,
    1042              :                                ekr);
    1043            9 :   ekr->last_http_status = last_http_status;
    1044            9 :   ekr->last_ec = last_ec;
    1045            9 :   if (NULL != jlimits)
    1046            4 :     ekr->jlimits = json_incref ((json_t *) jlimits);
    1047            9 :   ekr->h_wire = *h_wire;
    1048            9 :   ekr->exchange_url = GNUNET_strdup (exchange_url);
    1049              :   ekr->payto_uri.full_payto
    1050            9 :     = GNUNET_strdup (payto_uri.full_payto);
    1051            9 :   ekr->last_check = last_check;
    1052            9 :   ekr->kyc_ok = kyc_ok;
    1053            9 :   ekr->kc = kc;
    1054            9 :   ekr->in_aml_review = in_aml_review;
    1055            9 :   ekr->auth_ok = (NULL != access_token);
    1056            9 :   if ( (! ekr->auth_ok) ||
    1057            4 :        (NULL == ekr->jlimits) )
    1058              :   {
    1059              :     /* Figure out wire transfer instructions */
    1060            5 :     if (GNUNET_NO == kc->suspended)
    1061              :     {
    1062            4 :       MHD_suspend_connection (kc->connection);
    1063            4 :       kc->suspended = GNUNET_YES;
    1064              :     }
    1065            5 :     ekr->fo = TMH_EXCHANGES_keys4exchange (
    1066              :       exchange_url,
    1067              :       false,
    1068              :       &kyc_with_exchange,
    1069              :       ekr);
    1070            5 :     if (NULL == ekr->fo)
    1071              :     {
    1072            0 :       GNUNET_break (0);
    1073            0 :       ekr_finished (ekr);
    1074            0 :       return;
    1075              :     }
    1076            5 :     return;
    1077              :   }
    1078            4 :   ekr->access_token = *access_token;
    1079            4 :   ekr_finished (ekr);
    1080              : }
    1081              : 
    1082              : 
    1083              : /**
    1084              :  * Check the KYC status of an instance.
    1085              :  *
    1086              :  * @param mi instance to check KYC status of
    1087              :  * @param connection the MHD connection to handle
    1088              :  * @param[in,out] hc context with further information about the request
    1089              :  * @return MHD result code
    1090              :  */
    1091              : static MHD_RESULT
    1092           13 : get_instances_ID_kyc (
    1093              :   struct TMH_MerchantInstance *mi,
    1094              :   struct MHD_Connection *connection,
    1095              :   struct TMH_HandlerContext *hc)
    1096              : {
    1097           13 :   struct KycContext *kc = hc->ctx;
    1098              : 
    1099           13 :   if (NULL == kc)
    1100              :   {
    1101            9 :     kc = GNUNET_new (struct KycContext);
    1102            9 :     kc->mi = mi;
    1103            9 :     hc->ctx = kc;
    1104            9 :     hc->cc = &kyc_context_cleanup;
    1105            9 :     GNUNET_CONTAINER_DLL_insert (kc_head,
    1106              :                                  kc_tail,
    1107              :                                  kc);
    1108            9 :     kc->connection = connection;
    1109            9 :     kc->hc = hc;
    1110            9 :     kc->kycs_data = json_array ();
    1111            9 :     GNUNET_assert (NULL != kc->kycs_data);
    1112            9 :     TALER_MHD_parse_request_timeout (connection,
    1113              :                                      &kc->timeout);
    1114              :     {
    1115            9 :       uint64_t num = 0;
    1116              :       int val;
    1117              : 
    1118            9 :       TALER_MHD_parse_request_number (connection,
    1119              :                                       "lpt",
    1120              :                                       &num);
    1121            9 :       val = (int) num;
    1122            9 :       if ( (val < 0) ||
    1123              :            (val > TALER_EXCHANGE_KLPT_MAX) )
    1124              :       {
    1125              :         /* Protocol violation, but we can be graceful and
    1126              :            just ignore the long polling! */
    1127            0 :         GNUNET_break_op (0);
    1128            0 :         val = TALER_EXCHANGE_KLPT_NONE;
    1129              :       }
    1130            9 :       kc->lpt = (enum TALER_EXCHANGE_KycLongPollTarget) val;
    1131              :     }
    1132              :     kc->return_immediately
    1133            9 :       = (TALER_EXCHANGE_KLPT_NONE == kc->lpt);
    1134              :     /* process 'exchange_url' argument */
    1135            9 :     kc->exchange_url = MHD_lookup_connection_value (
    1136              :       connection,
    1137              :       MHD_GET_ARGUMENT_KIND,
    1138              :       "exchange_url");
    1139            9 :     if ( (NULL != kc->exchange_url) &&
    1140            7 :          ( (! TALER_url_valid_charset (kc->exchange_url)) ||
    1141            7 :            (! TALER_is_web_url (kc->exchange_url)) ) )
    1142              :     {
    1143            0 :       GNUNET_break_op (0);
    1144            0 :       return TALER_MHD_reply_with_error (
    1145              :         connection,
    1146              :         MHD_HTTP_BAD_REQUEST,
    1147              :         TALER_EC_GENERIC_PARAMETER_MALFORMED,
    1148              :         "exchange_url must be a valid HTTP(s) URL");
    1149              :     }
    1150              : 
    1151            9 :     TALER_MHD_parse_request_arg_auto (connection,
    1152              :                                       "h_wire",
    1153              :                                       &kc->h_wire,
    1154              :                                       kc->have_h_wire);
    1155              : 
    1156            9 :     if ( (TALER_EXCHANGE_KLPT_NONE != kc->lpt) &&
    1157            4 :          (! GNUNET_TIME_absolute_is_past (kc->timeout)) )
    1158              :     {
    1159            4 :       if (kc->have_h_wire)
    1160              :       {
    1161            2 :         struct TALER_MERCHANTDB_MerchantKycStatusChangeEventP ev = {
    1162            2 :           .header.size = htons (sizeof (ev)),
    1163            2 :           .header.type = htons (
    1164              :             TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_STATUS_CHANGED
    1165              :             ),
    1166              :           .h_wire = kc->h_wire
    1167              :         };
    1168              : 
    1169            4 :         kc->eh = TMH_db->event_listen (
    1170            2 :           TMH_db->cls,
    1171              :           &ev.header,
    1172              :           GNUNET_TIME_absolute_get_remaining (kc->timeout),
    1173              :           &kyc_change_cb,
    1174              :           kc);
    1175              :       }
    1176              :       else
    1177              :       {
    1178            2 :         struct GNUNET_DB_EventHeaderP hdr = {
    1179            2 :           .size = htons (sizeof (hdr)),
    1180            2 :           .type = htons (TALER_DBEVENT_MERCHANT_KYC_STATUS_CHANGED)
    1181              :         };
    1182              : 
    1183            4 :         kc->eh = TMH_db->event_listen (
    1184            2 :           TMH_db->cls,
    1185              :           &hdr,
    1186              :           GNUNET_TIME_absolute_get_remaining (kc->timeout),
    1187              :           &kyc_change_cb,
    1188              :           kc);
    1189              :       }
    1190              :     } /* end register LISTEN hooks */
    1191              :   } /* end 1st time initialization */
    1192              : 
    1193           13 :   if (GNUNET_SYSERR == kc->suspended)
    1194            0 :     return MHD_NO; /* during shutdown, we don't generate any more replies */
    1195           13 :   GNUNET_assert (GNUNET_NO == kc->suspended);
    1196              : 
    1197           13 :   if (NULL != kc->response)
    1198            3 :     return MHD_queue_response (connection,
    1199              :                                kc->response_code,
    1200              :                                kc->response);
    1201              : 
    1202              :   /* Check our database */
    1203              :   {
    1204              :     enum GNUNET_DB_QueryStatus qs;
    1205              : 
    1206           10 :     GNUNET_break (0 ==
    1207              :                   json_array_clear (kc->kycs_data));
    1208           10 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1209              :                 "Checking KYC status for %s (%d/%s)\n",
    1210              :                 mi->settings.id,
    1211              :                 kc->have_h_wire,
    1212              :                 kc->exchange_url);
    1213           10 :     qs = TMH_db->account_kyc_get_status (
    1214           10 :       TMH_db->cls,
    1215           10 :       mi->settings.id,
    1216           10 :       kc->have_h_wire
    1217              :       ? &kc->h_wire
    1218              :       : NULL,
    1219              :       kc->exchange_url,
    1220              :       &kyc_status_cb,
    1221              :       kc);
    1222           10 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1223              :                 "account_kyc_get_status returned %d records\n",
    1224              :                 (int) qs);
    1225           10 :     if (qs < 0)
    1226              :     {
    1227              :       /* Database error */
    1228            0 :       GNUNET_break (0);
    1229            0 :       if (GNUNET_YES == kc->suspended)
    1230              :       {
    1231              :         /* must have suspended before DB error, resume! */
    1232            0 :         MHD_resume_connection (connection);
    1233            0 :         kc->suspended = GNUNET_NO;
    1234              :       }
    1235            0 :       return TALER_MHD_reply_with_ec (
    1236              :         connection,
    1237              :         TALER_EC_GENERIC_DB_FETCH_FAILED,
    1238              :         "account_kyc_get_status");
    1239              :     }
    1240           10 :     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    1241              :     {
    1242              :       /* no matching accounts, could not have suspended */
    1243            2 :       GNUNET_assert (GNUNET_NO == kc->suspended);
    1244            2 :       return TALER_MHD_reply_static (connection,
    1245              :                                      MHD_HTTP_NO_CONTENT,
    1246              :                                      NULL,
    1247              :                                      NULL,
    1248              :                                      0);
    1249              :     }
    1250              :   }
    1251            8 :   if (GNUNET_YES == kc->suspended)
    1252            4 :     return MHD_YES;
    1253              :   /* Should have generated a response */
    1254            4 :   GNUNET_break (NULL != kc->response);
    1255            4 :   return MHD_queue_response (connection,
    1256              :                              kc->response_code,
    1257              :                              kc->response);
    1258              : }
    1259              : 
    1260              : 
    1261              : MHD_RESULT
    1262           13 : TMH_private_get_instances_ID_kyc (
    1263              :   const struct TMH_RequestHandler *rh,
    1264              :   struct MHD_Connection *connection,
    1265              :   struct TMH_HandlerContext *hc)
    1266              : {
    1267           13 :   struct TMH_MerchantInstance *mi = hc->instance;
    1268              : 
    1269              :   (void) rh;
    1270           13 :   return get_instances_ID_kyc (mi,
    1271              :                                connection,
    1272              :                                hc);
    1273              : }
    1274              : 
    1275              : 
    1276              : MHD_RESULT
    1277            0 : TMH_private_get_instances_default_ID_kyc (
    1278              :   const struct TMH_RequestHandler *rh,
    1279              :   struct MHD_Connection *connection,
    1280              :   struct TMH_HandlerContext *hc)
    1281              : {
    1282              :   struct TMH_MerchantInstance *mi;
    1283              : 
    1284              :   (void) rh;
    1285            0 :   mi = TMH_lookup_instance (hc->infix);
    1286            0 :   if (NULL == mi)
    1287              :   {
    1288            0 :     return TALER_MHD_reply_with_error (
    1289              :       connection,
    1290              :       MHD_HTTP_NOT_FOUND,
    1291              :       TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN,
    1292            0 :       hc->infix);
    1293              :   }
    1294            0 :   return get_instances_ID_kyc (mi,
    1295              :                                connection,
    1296              :                                hc);
    1297              : }
    1298              : 
    1299              : 
    1300              : /* end of taler-merchant-httpd_private-get-instances-ID-kyc.c */
        

Generated by: LCOV version 2.0-1