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

Generated by: LCOV version 1.14