LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_private-get-instances-ID-kyc.c (source / functions) Hit Total Coverage
Test: GNU Taler merchant coverage report Lines: 0 227 0.0 %
Date: 2022-08-25 06:17:04 Functions: 0 11 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of GNU Taler
       3             :   (C) 2021 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             : 
      31             : 
      32             : /**
      33             :  * We do not re-check an acceptable KYC status for
      34             :  * a month, as usually a KYC never expires.
      35             :  */
      36             : #define STALE_KYC_TIMEOUT GNUNET_TIME_UNIT_MONTHS
      37             : 
      38             : /**
      39             :  * How long should clients cache a KYC failure response?
      40             :  */
      41             : #define EXPIRATION_KYC_FAILURE GNUNET_TIME_relative_multiply ( \
      42             :     GNUNET_TIME_UNIT_MINUTES, 5)
      43             : 
      44             : /**
      45             :  * How long should clients cache a KYC success response?
      46             :  */
      47             : #define EXPIRATION_KYC_SUCCESS GNUNET_TIME_relative_multiply ( \
      48             :     GNUNET_TIME_UNIT_HOURS, 1)
      49             : 
      50             : 
      51             : /**
      52             :  * Information we keep per /kyc request.
      53             :  */
      54             : struct KycContext;
      55             : 
      56             : 
      57             : /**
      58             :  * Structure for tracking requests to the exchange's
      59             :  * ``/kyc-check`` API.
      60             :  */
      61             : struct ExchangeKycRequest
      62             : {
      63             :   /**
      64             :    * Kept in a DLL.
      65             :    */
      66             :   struct ExchangeKycRequest *next;
      67             : 
      68             :   /**
      69             :    * Kept in a DLL.
      70             :    */
      71             :   struct ExchangeKycRequest *prev;
      72             : 
      73             :   /**
      74             :    * Find operation where we connect to the respective exchange.
      75             :    */
      76             :   struct TMH_EXCHANGES_FindOperation *fo;
      77             : 
      78             :   /**
      79             :    * KYC request this exchange request is made for.
      80             :    */
      81             :   struct KycContext *kc;
      82             : 
      83             :   /**
      84             :    * Hash of the wire account (with salt) we are checking.
      85             :    */
      86             :   struct TALER_MerchantWireHashP h_wire;
      87             : 
      88             :   /**
      89             :    * Handle for the actual HTTP request to the exchange.
      90             :    */
      91             :   struct TALER_EXCHANGE_KycCheckHandle *kyc;
      92             : 
      93             :   /**
      94             :    * KYC number used by the exchange.
      95             :    */
      96             :   uint64_t exchange_kyc_serial;
      97             : 
      98             :   /**
      99             :    * Our account's payto URI.
     100             :    */
     101             :   char *payto_uri;
     102             : 
     103             :   /**
     104             :    * Base URL of the exchange.
     105             :    */
     106             :   char *exchange_url;
     107             : 
     108             :   /**
     109             :    * Timestamp when we last got a reply from the exchange.
     110             :    */
     111             :   struct GNUNET_TIME_Timestamp last_check;
     112             : 
     113             :   /**
     114             :    * Last KYC status returned by the exchange.
     115             :    */
     116             :   bool kyc_ok;
     117             : 
     118             : };
     119             : 
     120             : 
     121             : /**
     122             :  * Information we keep per /kyc request.
     123             :  */
     124             : struct KycContext
     125             : {
     126             :   /**
     127             :    * Stored in a DLL.
     128             :    */
     129             :   struct KycContext *next;
     130             : 
     131             :   /**
     132             :    * Stored in a DLL.
     133             :    */
     134             :   struct KycContext *prev;
     135             : 
     136             :   /**
     137             :    * Connection we are handling.
     138             :    */
     139             :   struct MHD_Connection *connection;
     140             : 
     141             :   /**
     142             :    * Instance we are serving.
     143             :    */
     144             :   struct TMH_MerchantInstance *mi;
     145             : 
     146             :   /**
     147             :    * Our handler context.
     148             :    */
     149             :   struct TMH_HandlerContext *hc;
     150             : 
     151             :   /**
     152             :    * Task to trigger on request timeout, or NULL.
     153             :    */
     154             :   struct GNUNET_SCHEDULER_Task *timeout_task;
     155             : 
     156             :   /**
     157             :    * Response to return, NULL if we don't have one yet.
     158             :    */
     159             :   struct MHD_Response *response;
     160             : 
     161             :   /**
     162             :    * JSON array where we are building up the array with
     163             :    * pending KYC operations.
     164             :    */
     165             :   json_t *pending_kycs;
     166             : 
     167             :   /**
     168             :    * JSON array where we are building up the array with
     169             :    * troubled KYC operations.
     170             :    */
     171             :   json_t *timeout_kycs;
     172             : 
     173             :   /**
     174             :    * Head of DLL of requests we are making to an
     175             :    * exchange to inquire about the latest KYC status.
     176             :    */
     177             :   struct ExchangeKycRequest *exchange_pending_head;
     178             : 
     179             :   /**
     180             :    * Tail of DLL of requests we are making to an
     181             :    * exchange to inquire about the latest KYC status.
     182             :    */
     183             :   struct ExchangeKycRequest *exchange_pending_tail;
     184             : 
     185             :   /**
     186             :    * Set to the exchange URL, or NULL to not filter by
     187             :    * exchange.
     188             :    */
     189             :   const char *exchange_url;
     190             : 
     191             :   /**
     192             :    * Set to the h_wire of the merchant account if
     193             :    * @a have_h_wire is true, used to filter by account.
     194             :    */
     195             :   struct TALER_MerchantWireHashP h_wire;
     196             : 
     197             :   /**
     198             :    * How long are we willing to wait for the exchange(s)?
     199             :    */
     200             :   struct GNUNET_TIME_Relative timeout;
     201             : 
     202             :   /**
     203             :    * HTTP status code to use for the reply, i.e 200 for "OK".
     204             :    * Special value UINT_MAX is used to indicate hard errors
     205             :    * (no reply, return #MHD_NO).
     206             :    */
     207             :   unsigned int response_code;
     208             : 
     209             :   /**
     210             :    * #GNUNET_NO if the @e connection was not suspended,
     211             :    * #GNUNET_YES if the @e connection was suspended,
     212             :    * #GNUNET_SYSERR if @e connection was resumed to as
     213             :    * part of #MH_force_pc_resume during shutdown.
     214             :    */
     215             :   enum GNUNET_GenericReturnValue suspended;
     216             : 
     217             :   /**
     218             :    * True if @e h_wire was given.
     219             :    */
     220             :   bool have_h_wire;
     221             : 
     222             :   /**
     223             :    * We're still waiting on the exchange to determine
     224             :    * the KYC status of our deposit(s).
     225             :    */
     226             :   bool kyc_serial_pending;
     227             : 
     228             : };
     229             : 
     230             : 
     231             : /**
     232             :  * Head of DLL.
     233             :  */
     234             : static struct KycContext *kc_head;
     235             : 
     236             : /**
     237             :  * Tail of DLL.
     238             :  */
     239             : static struct KycContext *kc_tail;
     240             : 
     241             : 
     242             : void
     243           0 : TMH_force_kyc_resume ()
     244             : {
     245           0 :   for (struct KycContext *kc = kc_head;
     246             :        NULL != kc;
     247           0 :        kc = kc->next)
     248             :   {
     249           0 :     if (NULL != kc->timeout_task)
     250             :     {
     251           0 :       GNUNET_SCHEDULER_cancel (kc->timeout_task);
     252           0 :       kc->timeout_task = NULL;
     253             :     }
     254           0 :     if (GNUNET_YES == kc->suspended)
     255             :     {
     256           0 :       kc->suspended = GNUNET_SYSERR;
     257           0 :       MHD_resume_connection (kc->connection);
     258             :     }
     259             :   }
     260           0 : }
     261             : 
     262             : 
     263             : /**
     264             :  * Custom cleanup routine for a `struct KycContext`.
     265             :  *
     266             :  * @param cls the `struct KycContext` to clean up.
     267             :  */
     268             : static void
     269           0 : kyc_context_cleanup (void *cls)
     270             : {
     271           0 :   struct KycContext *kc = cls;
     272             :   struct ExchangeKycRequest *ekr;
     273             : 
     274           0 :   while (NULL != (ekr = kc->exchange_pending_head))
     275             :   {
     276           0 :     GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
     277             :                                  kc->exchange_pending_tail,
     278             :                                  ekr);
     279           0 :     if (NULL != ekr->kyc)
     280             :     {
     281           0 :       TALER_EXCHANGE_kyc_check_cancel (ekr->kyc);
     282           0 :       ekr->kyc = NULL;
     283             :     }
     284           0 :     if (NULL != ekr->fo)
     285             :     {
     286           0 :       TMH_EXCHANGES_find_exchange_cancel (ekr->fo);
     287           0 :       ekr->fo = NULL;
     288             :     }
     289           0 :     GNUNET_free (ekr->exchange_url);
     290           0 :     GNUNET_free (ekr->payto_uri);
     291           0 :     GNUNET_free (ekr);
     292             :   }
     293           0 :   if (NULL != kc->timeout_task)
     294             :   {
     295           0 :     GNUNET_SCHEDULER_cancel (kc->timeout_task);
     296           0 :     kc->timeout_task = NULL;
     297             :   }
     298           0 :   if (NULL != kc->response)
     299             :   {
     300           0 :     MHD_destroy_response (kc->response);
     301           0 :     kc->response = NULL;
     302             :   }
     303           0 :   GNUNET_CONTAINER_DLL_remove (kc_head,
     304             :                                kc_tail,
     305             :                                kc);
     306           0 :   json_decref (kc->pending_kycs);
     307           0 :   json_decref (kc->timeout_kycs);
     308           0 :   GNUNET_free (kc);
     309           0 : }
     310             : 
     311             : 
     312             : /**
     313             :  * Resume the given KYC context and send the given response.
     314             :  * Stores the response in the @a kc and signals MHD to resume
     315             :  * the connection.  Also ensures MHD runs immediately.
     316             :  *
     317             :  * @param kc KYC context
     318             :  * @param response_code response code to use
     319             :  * @param response response data to send back
     320             :  */
     321             : static void
     322           0 : resume_kyc_with_response (struct KycContext *kc,
     323             :                           unsigned int response_code,
     324             :                           struct MHD_Response *response)
     325             : {
     326             :   char dat[128];
     327             : 
     328           0 :   kc->response_code = response_code;
     329           0 :   kc->response = response;
     330           0 :   switch (response_code)
     331             :   {
     332           0 :   case MHD_HTTP_OK:
     333             :     /* KYC failed, cache briefly */
     334           0 :     TALER_MHD_get_date_string (GNUNET_TIME_relative_to_absolute (
     335             :                                  EXPIRATION_KYC_FAILURE),
     336             :                                dat);
     337           0 :     GNUNET_break (MHD_YES ==
     338             :                   MHD_add_response_header (response,
     339             :                                            MHD_HTTP_HEADER_EXPIRES,
     340             :                                            dat));
     341           0 :     GNUNET_break (MHD_YES ==
     342             :                   MHD_add_response_header (response,
     343             :                                            MHD_HTTP_HEADER_CACHE_CONTROL,
     344             :                                            "max-age=300"));
     345           0 :     break;
     346           0 :   case MHD_HTTP_NO_CONTENT:
     347             :     /* KYC passed, cache for a long time! */
     348           0 :     TALER_MHD_get_date_string (GNUNET_TIME_relative_to_absolute (
     349             :                                  EXPIRATION_KYC_SUCCESS),
     350             :                                dat);
     351           0 :     GNUNET_break (MHD_YES ==
     352             :                   MHD_add_response_header (response,
     353             :                                            MHD_HTTP_HEADER_EXPIRES,
     354             :                                            dat));
     355           0 :     GNUNET_break (MHD_YES ==
     356             :                   MHD_add_response_header (response,
     357             :                                            MHD_HTTP_HEADER_CACHE_CONTROL,
     358             :                                            "max-age=3600"));
     359           0 :     break;
     360           0 :   case MHD_HTTP_BAD_GATEWAY:
     361             :   case MHD_HTTP_GATEWAY_TIMEOUT:
     362           0 :     break; /* no caching */
     363             :   }
     364           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     365             :               "Resuming /kyc handling as exchange interaction is done (%u)\n",
     366             :               response_code);
     367           0 :   if (NULL != kc->timeout_task)
     368             :   {
     369           0 :     GNUNET_SCHEDULER_cancel (kc->timeout_task);
     370           0 :     kc->timeout_task = NULL;
     371             :   }
     372           0 :   GNUNET_assert (GNUNET_YES == kc->suspended);
     373           0 :   kc->suspended = GNUNET_NO;
     374           0 :   MHD_resume_connection (kc->connection);
     375           0 :   TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
     376           0 : }
     377             : 
     378             : 
     379             : /**
     380             :  * Handle a timeout for the processing of the kyc request.
     381             :  *
     382             :  * @param cls our `struct KycContext`
     383             :  */
     384             : static void
     385           0 : handle_kyc_timeout (void *cls)
     386             : {
     387           0 :   struct KycContext *kc = cls;
     388             :   struct ExchangeKycRequest *ekr;
     389             : 
     390           0 :   kc->timeout_task = NULL;
     391           0 :   while (NULL != (ekr = kc->exchange_pending_head))
     392             :   {
     393           0 :     GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
     394             :                                  kc->exchange_pending_tail,
     395             :                                  ekr);
     396           0 :     if (NULL != ekr->kyc)
     397             :     {
     398           0 :       TALER_EXCHANGE_kyc_check_cancel (ekr->kyc);
     399           0 :       ekr->kyc = NULL;
     400             :     }
     401           0 :     if (NULL != ekr->fo)
     402             :     {
     403           0 :       TMH_EXCHANGES_find_exchange_cancel (ekr->fo);
     404           0 :       ekr->fo = NULL;
     405             :     }
     406           0 :     GNUNET_assert (
     407             :       0 ==
     408             :       json_array_append_new (
     409             :         kc->timeout_kycs,
     410             :         GNUNET_JSON_PACK (
     411             :           GNUNET_JSON_pack_string ("exchange_url",
     412             :                                    ekr->exchange_url),
     413             :           GNUNET_JSON_pack_uint64 ("exchange_code",
     414             :                                    TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT),
     415             :           GNUNET_JSON_pack_uint64 ("exchange_http_status",
     416             :                                    0))));
     417           0 :     GNUNET_free (ekr->exchange_url);
     418           0 :     GNUNET_free (ekr->payto_uri);
     419           0 :     GNUNET_free (ekr);
     420             :   }
     421           0 :   GNUNET_assert (GNUNET_YES == kc->suspended);
     422           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     423             :               "Resuming KYC with gateway timeout\n");
     424           0 :   resume_kyc_with_response (
     425             :     kc,
     426             :     MHD_HTTP_GATEWAY_TIMEOUT,
     427           0 :     TALER_MHD_MAKE_JSON_PACK (
     428             :       GNUNET_JSON_pack_array_incref ("pending_kycs",
     429             :                                      kc->pending_kycs),
     430             :       GNUNET_JSON_pack_array_incref ("timeout_kycs",
     431             :                                      kc->timeout_kycs)));
     432           0 : }
     433             : 
     434             : 
     435             : /**
     436             :  * We are done with the KYC request @a ekr.
     437             :  * Remove it from the work list and check if
     438             :  * we are done overall.
     439             :  *
     440             :  * @param[in] ekr key request that is done (and will be freed)
     441             :  */
     442             : static void
     443           0 : ekr_finished (struct ExchangeKycRequest *ekr)
     444             : {
     445           0 :   struct KycContext *kc = ekr->kc;
     446             : 
     447           0 :   GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
     448             :                                kc->exchange_pending_tail,
     449             :                                ekr);
     450           0 :   GNUNET_free (ekr->exchange_url);
     451           0 :   GNUNET_free (ekr->payto_uri);
     452           0 :   GNUNET_free (ekr);
     453           0 :   if (NULL != kc->exchange_pending_head)
     454           0 :     return; /* wait for more */
     455             :   /* All exchange requests done, create final
     456             :      big response from cummulated replies */
     457           0 :   if ( (0 == json_array_size (kc->pending_kycs)) &&
     458           0 :        (0 == json_array_size (kc->timeout_kycs)) )
     459             :   {
     460             :     /* special case: all KYC operations did succeed
     461             :        after we asked at the exchanges => 204 */
     462             :     struct MHD_Response *response;
     463             : 
     464           0 :     response = MHD_create_response_from_buffer (0,
     465             :                                                 "",
     466             :                                                 MHD_RESPMEM_PERSISTENT);
     467           0 :     resume_kyc_with_response (kc,
     468             :                               MHD_HTTP_NO_CONTENT,
     469             :                               response);
     470           0 :     return;
     471             :   }
     472           0 :   resume_kyc_with_response (
     473             :     kc,
     474             :     kc->response_code, /* MHD_HTTP_OK or MHD_HTTP_BAD_GATEWAY */
     475           0 :     TALER_MHD_MAKE_JSON_PACK (
     476             :       GNUNET_JSON_pack_array_incref ("pending_kycs",
     477             :                                      kc->pending_kycs),
     478             :       GNUNET_JSON_pack_array_incref ("timeout_kycs",
     479             :                                      kc->timeout_kycs)));
     480             : }
     481             : 
     482             : 
     483             : /**
     484             :  * Function called with the result of a KYC check.
     485             :  *
     486             :  * @param cls a `struct ExchangeKycRequest *`
     487             :  * @param ks the account's KYC status details
     488             :  */
     489             : static void
     490           0 : exchange_check_cb (void *cls,
     491             :                    const struct TALER_EXCHANGE_KycStatus *ks)
     492             : {
     493           0 :   struct ExchangeKycRequest *ekr = cls;
     494           0 :   struct KycContext *kc = ekr->kc;
     495             : 
     496           0 :   ekr->kyc = NULL;
     497           0 :   switch (ks->http_status)
     498             :   {
     499           0 :   case MHD_HTTP_OK:
     500             :     {
     501             :       enum GNUNET_DB_QueryStatus qs;
     502             : 
     503           0 :       qs = TMH_db->account_kyc_set_status (TMH_db->cls,
     504           0 :                                            kc->mi->settings.id,
     505           0 :                                            &ekr->h_wire,
     506           0 :                                            ekr->exchange_url,
     507             :                                            ekr->exchange_kyc_serial,
     508             :                                            &ks->details.success.exchange_sig,
     509             :                                            &ks->details.success.exchange_pub,
     510             :                                            ks->details.success.timestamp,
     511             :                                            true);
     512           0 :       if (qs < 0)
     513             :       {
     514           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     515             :                     "Failed to store KYC status in database!\n");
     516             :       }
     517             :     }
     518           0 :     break;
     519           0 :   case MHD_HTTP_ACCEPTED:
     520           0 :     GNUNET_assert (
     521             :       0 ==
     522             :       json_array_append_new (
     523             :         kc->pending_kycs,
     524             :         GNUNET_JSON_PACK (
     525             :           GNUNET_JSON_pack_string ("kyc_url",
     526             :                                    ks->details.accepted.kyc_url),
     527             :           GNUNET_JSON_pack_string ("exchange_url",
     528             :                                    ekr->exchange_url),
     529             :           GNUNET_JSON_pack_string ("payto_uri",
     530             :                                    ekr->payto_uri))));
     531           0 :     break;
     532           0 :   case MHD_HTTP_NO_CONTENT:
     533             :     {
     534             :       struct GNUNET_TIME_Timestamp now;
     535             :       enum GNUNET_DB_QueryStatus qs;
     536             : 
     537           0 :       now = GNUNET_TIME_timestamp_get ();
     538           0 :       qs = TMH_db->account_kyc_set_status (TMH_db->cls,
     539           0 :                                            kc->mi->settings.id,
     540           0 :                                            &ekr->h_wire,
     541           0 :                                            ekr->exchange_url,
     542             :                                            ekr->exchange_kyc_serial,
     543             :                                            NULL,
     544             :                                            NULL,
     545             :                                            now,
     546             :                                            true);
     547           0 :       if (qs < 0)
     548             :       {
     549           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     550             :                     "Failed to store KYC status in database!\n");
     551             :       }
     552             :     }
     553           0 :     break;
     554           0 :   default:
     555           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     556             :                 "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n",
     557             :                 ks->http_status,
     558             :                 ks->ec);
     559           0 :     kc->response_code = MHD_HTTP_BAD_GATEWAY;
     560           0 :     GNUNET_assert (
     561             :       0 ==
     562             :       json_array_append_new (
     563             :         kc->timeout_kycs,
     564             :         GNUNET_JSON_PACK (
     565             :           GNUNET_JSON_pack_string ("exchange_url",
     566             :                                    ekr->exchange_url),
     567             :           GNUNET_JSON_pack_uint64 ("exchange_code",
     568             :                                    ks->ec),
     569             :           GNUNET_JSON_pack_uint64 ("exchange_http_status",
     570             :                                    ks->http_status))));
     571             :   }
     572           0 :   ekr_finished (ekr);
     573           0 : }
     574             : 
     575             : 
     576             : /**
     577             :  * Function called with the result of a #TMH_EXCHANGES_find_exchange()
     578             :  * operation.  Runs the KYC check against the exchange.
     579             :  *
     580             :  * @param cls closure with our `struct ExchangeKycRequest *`
     581             :  * @param hr HTTP response details
     582             :  * @param eh handle to the exchange context
     583             :  * @param payto_uri payto://-URI of the exchange
     584             :  * @param wire_fee current applicable wire fee for dealing with @a eh, NULL if not available
     585             :  * @param exchange_trusted true if this exchange is trusted by config
     586             :  */
     587             : static void
     588           0 : kyc_with_exchange (void *cls,
     589             :                    const struct TALER_EXCHANGE_HttpResponse *hr,
     590             :                    struct TALER_EXCHANGE_Handle *eh,
     591             :                    const char *payto_uri,
     592             :                    const struct TALER_Amount *wire_fee,
     593             :                    bool exchange_trusted)
     594             : {
     595           0 :   struct ExchangeKycRequest *ekr = cls;
     596           0 :   struct KycContext *kc = ekr->kc;
     597             :   struct TALER_PaytoHashP h_payto;
     598             : 
     599             :   (void) payto_uri;
     600             :   (void) wire_fee;
     601             :   (void) exchange_trusted;
     602           0 :   ekr->fo = NULL;
     603           0 :   if (MHD_HTTP_OK != hr->http_status)
     604             :   {
     605           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     606             :                 "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n",
     607             :                 hr->http_status,
     608             :                 hr->ec);
     609           0 :     kc->response_code = MHD_HTTP_BAD_GATEWAY;
     610           0 :     GNUNET_assert (
     611             :       0 ==
     612             :       json_array_append_new (
     613             :         kc->timeout_kycs,
     614             :         GNUNET_JSON_PACK (
     615             :           GNUNET_JSON_pack_string ("exchange_url",
     616             :                                    ekr->exchange_url),
     617             :           GNUNET_JSON_pack_uint64 ("exchange_code",
     618             :                                    hr->ec),
     619             :           GNUNET_JSON_pack_uint64 ("exchange_http_status",
     620             :                                    hr->http_status))));
     621           0 :     ekr_finished (ekr);
     622           0 :     return;
     623             :   }
     624           0 :   TALER_payto_hash (ekr->payto_uri,
     625             :                     &h_payto);
     626           0 :   ekr->kyc = TALER_EXCHANGE_kyc_check (
     627             :     eh,
     628             :     ekr->exchange_kyc_serial,
     629             :     &h_payto,
     630             :     /* FIXME: get from settings! */
     631             :     TALER_KYCLOGIC_KYC_UT_BUSINESS,
     632             :     kc->timeout,
     633             :     &exchange_check_cb,
     634             :     ekr);
     635             : }
     636             : 
     637             : 
     638             : /**
     639             :  * Function called from ``account_kyc_get_status``
     640             :  * with KYC status information for this merchant.
     641             :  *
     642             :  * @param cls our `struct KycContext *`
     643             :  * @param h_wire hash of the wire account
     644             :  * @param exchange_kyc_serial serial number for the KYC process at the exchange, 0 if unknown
     645             :  * @param payto_uri payto:// URI of the merchant's bank account
     646             :  * @param exchange_url base URL of the exchange for which this is a status
     647             :  * @param last_check when did we last get an update on our KYC status from the exchange
     648             :  * @param kyc_ok true if we satisfied the KYC requirements
     649             :  */
     650             : static void
     651           0 : kyc_status_cb (void *cls,
     652             :                const struct TALER_MerchantWireHashP *h_wire,
     653             :                uint64_t exchange_kyc_serial,
     654             :                const char *payto_uri,
     655             :                const char *exchange_url,
     656             :                struct GNUNET_TIME_Timestamp last_check,
     657             :                bool kyc_ok)
     658             : {
     659           0 :   struct KycContext *kc = cls;
     660             :   struct ExchangeKycRequest *ekr;
     661             : 
     662           0 :   if (kyc_ok &&
     663           0 :       (GNUNET_TIME_relative_cmp (
     664             :          GNUNET_TIME_absolute_get_duration (last_check.abs_time),
     665             :          <,
     666             :          STALE_KYC_TIMEOUT)) )
     667           0 :     return; /* KYC ok, ignore! */
     668           0 :   if (0 == exchange_kyc_serial)
     669             :   {
     670           0 :     kc->kyc_serial_pending = true;
     671           0 :     return;
     672             :   }
     673           0 :   kc->response_code = MHD_HTTP_ACCEPTED;
     674           0 :   ekr = GNUNET_new (struct ExchangeKycRequest);
     675           0 :   GNUNET_CONTAINER_DLL_insert (kc->exchange_pending_head,
     676             :                                kc->exchange_pending_tail,
     677             :                                ekr);
     678           0 :   ekr->h_wire = *h_wire;
     679           0 :   ekr->exchange_kyc_serial = exchange_kyc_serial;
     680           0 :   ekr->exchange_url = GNUNET_strdup (exchange_url);
     681           0 :   ekr->payto_uri = GNUNET_strdup (payto_uri);
     682           0 :   ekr->last_check = last_check;
     683           0 :   ekr->kyc_ok = kyc_ok;
     684           0 :   ekr->kc = kc;
     685           0 :   ekr->fo = TMH_EXCHANGES_find_exchange (exchange_url,
     686             :                                          NULL,
     687             :                                          GNUNET_NO,
     688             :                                          &kyc_with_exchange,
     689             :                                          ekr);
     690             : }
     691             : 
     692             : 
     693             : /**
     694             :  * Check the KYC status of an instance.
     695             :  *
     696             :  * @param mi instance to check KYC status of
     697             :  * @param connection the MHD connection to handle
     698             :  * @param[in,out] hc context with further information about the request
     699             :  * @return MHD result code
     700             :  */
     701             : static MHD_RESULT
     702           0 : get_instances_ID_kyc (struct TMH_MerchantInstance *mi,
     703             :                       struct MHD_Connection *connection,
     704             :                       struct TMH_HandlerContext *hc)
     705             : {
     706           0 :   struct KycContext *kc = hc->ctx;
     707             : 
     708           0 :   if (NULL == kc)
     709             :   {
     710           0 :     kc = GNUNET_new (struct KycContext);
     711           0 :     kc->mi = mi;
     712           0 :     hc->ctx = kc;
     713           0 :     hc->cc = &kyc_context_cleanup;
     714           0 :     GNUNET_CONTAINER_DLL_insert (kc_head,
     715             :                                  kc_tail,
     716             :                                  kc);
     717           0 :     kc->connection = connection;
     718           0 :     kc->hc = hc;
     719           0 :     kc->pending_kycs = json_array ();
     720           0 :     GNUNET_assert (NULL != kc->pending_kycs);
     721           0 :     kc->timeout_kycs = json_array ();
     722           0 :     GNUNET_assert (NULL != kc->timeout_kycs);
     723             : 
     724             :     /* process 'timeout_ms' argument */
     725             :     {
     726             :       const char *long_poll_timeout_s;
     727             : 
     728             :       long_poll_timeout_s
     729           0 :         = MHD_lookup_connection_value (connection,
     730             :                                        MHD_GET_ARGUMENT_KIND,
     731             :                                        "timeout_ms");
     732           0 :       if (NULL != long_poll_timeout_s)
     733             :       {
     734             :         unsigned int timeout_ms;
     735             :         char dummy;
     736             : 
     737           0 :         if (1 != sscanf (long_poll_timeout_s,
     738             :                          "%u%c",
     739             :                          &timeout_ms,
     740             :                          &dummy))
     741             :         {
     742           0 :           GNUNET_break_op (0);
     743           0 :           return TALER_MHD_reply_with_error (connection,
     744             :                                              MHD_HTTP_BAD_REQUEST,
     745             :                                              TALER_EC_GENERIC_PARAMETER_MALFORMED,
     746             :                                              "timeout_ms must be non-negative number");
     747             :         }
     748           0 :         kc->timeout = GNUNET_TIME_relative_multiply (
     749             :           GNUNET_TIME_UNIT_MILLISECONDS,
     750             :           timeout_ms);
     751             :         kc->timeout_task
     752           0 :           = GNUNET_SCHEDULER_add_delayed (kc->timeout,
     753             :                                           &handle_kyc_timeout,
     754             :                                           kc);
     755             :       }
     756             :     } /* end timeout processing */
     757             : 
     758             :     /* process 'exchange_url' argument */
     759           0 :     kc->exchange_url = MHD_lookup_connection_value (connection,
     760             :                                                     MHD_GET_ARGUMENT_KIND,
     761             :                                                     "exchange_url");
     762           0 :     if ( (NULL != kc->exchange_url) &&
     763           0 :          (! TALER_url_valid_charset (kc->exchange_url) ||
     764           0 :           ( (0 != strncasecmp (kc->exchange_url,
     765             :                                "http://",
     766           0 :                                strlen ("http://"))) &&
     767           0 :             (0 != strncasecmp (kc->exchange_url,
     768             :                                "https://",
     769             :                                strlen ("https://"))) ) ) )
     770             :     {
     771           0 :       GNUNET_break_op (0);
     772           0 :       return TALER_MHD_reply_with_error (connection,
     773             :                                          MHD_HTTP_BAD_REQUEST,
     774             :                                          TALER_EC_GENERIC_PARAMETER_MALFORMED,
     775             :                                          "exchange_url must be a valid HTTP(s) URL");
     776             :     }
     777             : 
     778             :     /* process 'h_wire' argument */
     779             :     {
     780             :       const char *h_wire_s;
     781             : 
     782             :       h_wire_s
     783           0 :         = MHD_lookup_connection_value (connection,
     784             :                                        MHD_GET_ARGUMENT_KIND,
     785             :                                        "h_wire");
     786           0 :       if (NULL != h_wire_s)
     787             :       {
     788           0 :         if (GNUNET_OK !=
     789           0 :             GNUNET_STRINGS_string_to_data (h_wire_s,
     790             :                                            strlen (h_wire_s),
     791           0 :                                            &kc->h_wire,
     792             :                                            sizeof (kc->h_wire)))
     793             :         {
     794           0 :           GNUNET_break_op (0);
     795           0 :           return TALER_MHD_reply_with_error (connection,
     796             :                                              MHD_HTTP_BAD_REQUEST,
     797             :                                              TALER_EC_GENERIC_PARAMETER_MALFORMED,
     798             :                                              "h_wire must be Crockford base32 encoded hash");
     799             :         }
     800           0 :         kc->have_h_wire = true;
     801             :       }
     802             :     } /* end of h_wire processing */
     803             : 
     804             :     /* Check our database */
     805             :     {
     806             :       enum GNUNET_DB_QueryStatus qs;
     807             : 
     808           0 :       qs = TMH_db->account_kyc_get_status (TMH_db->cls,
     809           0 :                                            mi->settings.id,
     810           0 :                                            kc->have_h_wire
     811             :                                            ? &kc->h_wire
     812             :                                            : NULL,
     813             :                                            kc->exchange_url,
     814             :                                            &kyc_status_cb,
     815             :                                            kc);
     816           0 :       if (qs < 0)
     817             :       {
     818           0 :         GNUNET_break (0);
     819           0 :         return TALER_MHD_reply_with_ec (connection,
     820             :                                         TALER_EC_GENERIC_DB_FETCH_FAILED,
     821             :                                         "account_kyc_get_status");
     822             :       }
     823             :     }
     824           0 :     if (kc->kyc_serial_pending)
     825             :     {
     826           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     827             :                   "Exchange legitimization UUID unknown, assuming KYC pending\n");
     828           0 :       return TALER_MHD_REPLY_JSON_PACK (
     829             :         connection,
     830             :         MHD_HTTP_SERVICE_UNAVAILABLE,
     831             :         GNUNET_JSON_pack_string ("hint",
     832             :                                  "awaiting legitimization UUID"));
     833             :     }
     834           0 :     if (NULL == kc->exchange_pending_head)
     835           0 :       return TALER_MHD_reply_static (connection,
     836             :                                      MHD_HTTP_NO_CONTENT,
     837             :                                      NULL,
     838             :                                      NULL,
     839             :                                      0);
     840           0 :     MHD_suspend_connection (connection);
     841           0 :     kc->suspended = GNUNET_YES;
     842           0 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     843             :                 "Suspending KYC request handling while checking with the exchange(s)\n");
     844           0 :     return MHD_YES;
     845             :   }
     846           0 :   if (GNUNET_SYSERR == kc->suspended)
     847           0 :     return MHD_NO; /* during shutdown, we don't generate any more replies */
     848           0 :   GNUNET_assert (GNUNET_NO == kc->suspended);
     849           0 :   if (0 != kc->response_code)
     850             :   {
     851             :     /* We are *done* processing the request, just queue the response (!) */
     852           0 :     if (UINT_MAX == kc->response_code)
     853             :     {
     854           0 :       GNUNET_break (0);
     855           0 :       return MHD_NO; /* hard error */
     856             :     }
     857           0 :     return MHD_queue_response (connection,
     858             :                                kc->response_code,
     859             :                                kc->response);
     860             :   }
     861             :   /* we should never get here */
     862           0 :   GNUNET_break (0);
     863           0 :   return MHD_NO;
     864             : }
     865             : 
     866             : 
     867             : MHD_RESULT
     868           0 : TMH_private_get_instances_ID_kyc (const struct TMH_RequestHandler *rh,
     869             :                                   struct MHD_Connection *connection,
     870             :                                   struct TMH_HandlerContext *hc)
     871             : {
     872           0 :   struct TMH_MerchantInstance *mi = hc->instance;
     873             : 
     874             :   (void) rh;
     875           0 :   return get_instances_ID_kyc (mi,
     876             :                                connection,
     877             :                                hc);
     878             : }
     879             : 
     880             : 
     881             : MHD_RESULT
     882           0 : TMH_private_get_instances_default_ID_kyc (const struct TMH_RequestHandler *rh,
     883             :                                           struct MHD_Connection *connection,
     884             :                                           struct TMH_HandlerContext *hc)
     885             : {
     886             :   struct TMH_MerchantInstance *mi;
     887             : 
     888             :   (void) rh;
     889           0 :   mi = TMH_lookup_instance (hc->infix);
     890           0 :   if (NULL == mi)
     891             :   {
     892           0 :     return TALER_MHD_reply_with_error (connection,
     893             :                                        MHD_HTTP_NOT_FOUND,
     894             :                                        TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN,
     895           0 :                                        hc->infix);
     896             :   }
     897           0 :   return get_instances_ID_kyc (mi,
     898             :                                connection,
     899             :                                hc);
     900             : }
     901             : 
     902             : 
     903             : /* end of taler-merchant-httpd_private-get-instances-ID-kyc.c */

Generated by: LCOV version 1.14