merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

taler-merchant-httpd_get-private-kyc.c (46750B)


      1 /*
      2   This file is part of GNU Taler
      3   (C) 2021-2026 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 src/backend/taler-merchant-httpd_get-private-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_exchanges.h"
     27 #include "taler-merchant-httpd_get-private-kyc.h"
     28 #include "taler-merchant-httpd_helper.h"
     29 #include "taler-merchant-httpd_get-exchanges.h"
     30 #include <taler/taler_json_lib.h>
     31 #include <taler/taler_templating_lib.h>
     32 #include <taler/taler_dbevents.h>
     33 #include <regex.h>
     34 #include "merchant-database/account_kyc_get_status.h"
     35 #include "merchant-database/event_listen.h"
     36 
     37 /**
     38  * Information we keep per /kyc request.
     39  */
     40 struct KycContext;
     41 
     42 
     43 /**
     44  * Structure for tracking requests to the exchange's
     45  * ``/kyc-check`` API.
     46  */
     47 struct ExchangeKycRequest
     48 {
     49   /**
     50    * Kept in a DLL.
     51    */
     52   struct ExchangeKycRequest *next;
     53 
     54   /**
     55    * Kept in a DLL.
     56    */
     57   struct ExchangeKycRequest *prev;
     58 
     59   /**
     60    * Find operation where we connect to the respective exchange.
     61    */
     62   struct TMH_EXCHANGES_KeysOperation *fo;
     63 
     64   /**
     65    * JSON array of payto-URIs with KYC auth wire transfer
     66    * instructions.  Provided if @e auth_ok is false and
     67    * @e kyc_auth_conflict is false.
     68    */
     69   json_t *pkaa;
     70 
     71   /**
     72    * The keys of the exchange.
     73    */
     74   struct TALER_EXCHANGE_Keys *keys;
     75 
     76   /**
     77    * KYC request this exchange request is made for.
     78    */
     79   struct KycContext *kc;
     80 
     81   /**
     82    * JSON array of AccountLimits that apply, NULL if
     83    * unknown (and likely defaults apply).
     84    */
     85   json_t *jlimits;
     86 
     87   /**
     88    * Our account's payto URI.
     89    */
     90   struct TALER_FullPayto payto_uri;
     91 
     92   /**
     93    * Base URL of the exchange.
     94    */
     95   char *exchange_url;
     96 
     97   /**
     98    * Hash of the wire account (with salt) we are checking.
     99    */
    100   struct TALER_MerchantWireHashP h_wire;
    101 
    102   /**
    103    * Current access token for the KYC SPA. Only set
    104    * if @e auth_ok is true.
    105    */
    106   struct TALER_AccountAccessTokenP access_token;
    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 HTTP status code obtained via /kyc-check from the exchange.
    115    */
    116   unsigned int last_http_status;
    117 
    118   /**
    119    * Last Taler error code returned from /kyc-check.
    120    */
    121   enum TALER_ErrorCode last_ec;
    122 
    123   /**
    124    * True if this account cannot work at this exchange because KYC auth is
    125    * impossible.
    126    */
    127   bool kyc_auth_conflict;
    128 
    129   /**
    130    * We could not get /keys from the exchange.
    131    */
    132   bool no_keys;
    133 
    134   /**
    135    * True if @e access_token is available.
    136    */
    137   bool auth_ok;
    138 
    139   /**
    140    * True if we believe no KYC is currently required
    141    * for this account at this exchange.
    142    */
    143   bool kyc_ok;
    144 
    145   /**
    146    * True if the exchange exposed to us that the account
    147    * is currently under AML review.
    148    */
    149   bool in_aml_review;
    150 
    151 };
    152 
    153 
    154 /**
    155  * Information we keep per /kyc request.
    156  */
    157 struct KycContext
    158 {
    159   /**
    160    * Stored in a DLL.
    161    */
    162   struct KycContext *next;
    163 
    164   /**
    165    * Stored in a DLL.
    166    */
    167   struct KycContext *prev;
    168 
    169   /**
    170    * Connection we are handling.
    171    */
    172   struct MHD_Connection *connection;
    173 
    174   /**
    175    * Instance we are serving.
    176    */
    177   struct TMH_MerchantInstance *mi;
    178 
    179   /**
    180    * Our handler context.
    181    */
    182   struct TMH_HandlerContext *hc;
    183 
    184   /**
    185    * Response to return, NULL if we don't have one yet.
    186    */
    187   struct MHD_Response *response;
    188 
    189   /**
    190    * JSON array where we are building up the array with
    191    * pending KYC operations.
    192    */
    193   json_t *kycs_data;
    194 
    195   /**
    196    * Head of DLL of requests we are making to an
    197    * exchange to inquire about the latest KYC status.
    198    */
    199   struct ExchangeKycRequest *exchange_pending_head;
    200 
    201   /**
    202    * Tail of DLL of requests we are making to an
    203    * exchange to inquire about the latest KYC status.
    204    */
    205   struct ExchangeKycRequest *exchange_pending_tail;
    206 
    207   /**
    208    * Notification handler from database on changes
    209    * to the KYC status.
    210    */
    211   struct GNUNET_DB_EventHandler *eh;
    212 
    213   /**
    214    * Set to the exchange URL, or NULL to not filter by
    215    * exchange.  "exchange_url" query parameter.
    216    */
    217   const char *exchange_url;
    218 
    219   /**
    220    * How long are we willing to wait for the exchange(s)?
    221    * Based on "timeout_ms" query parameter.
    222    */
    223   struct GNUNET_TIME_Absolute timeout;
    224 
    225   /**
    226    * Set to the h_wire of the merchant account if
    227    * @a have_h_wire is true, used to filter by account.
    228    * Set from "h_wire" query parameter.
    229    */
    230   struct TALER_MerchantWireHashP h_wire;
    231 
    232   /**
    233    * Set to the Etag of a response already known to the
    234    * client. We should only return from long-polling
    235    * on timeout (with "Not Modified") or when the Etag
    236    * of the response differs from what is given here.
    237    * Only set if @a have_lp_not_etag is true.
    238    * Set from "lp_etag" query parameter.
    239    */
    240   struct GNUNET_ShortHashCode lp_not_etag;
    241 
    242   /**
    243    * Specifies what status change we are long-polling for.  If specified, the
    244    * endpoint will only return once the status *matches* the given value.  If
    245    * multiple accounts or exchanges match the query, any account reaching the
    246    * STATUS will cause the response to be returned.
    247    */
    248   const char *lp_status;
    249 
    250   /**
    251    * Specifies what status change we are long-polling for.  If specified, the
    252    * endpoint will only return once the status no longer matches the given
    253    * value.  If multiple accounts or exchanges *no longer matches* the given
    254    * STATUS will cause the response to be returned.
    255    */
    256   const char *lp_not_status;
    257 
    258   /**
    259    * #GNUNET_NO if the @e connection was not suspended,
    260    * #GNUNET_YES if the @e connection was suspended,
    261    * #GNUNET_SYSERR if @e connection was resumed to as
    262    * part of #MH_force_pc_resume during shutdown.
    263    */
    264   enum GNUNET_GenericReturnValue suspended;
    265 
    266   /**
    267    * What state are we long-polling for? "lpt" argument.
    268    */
    269   enum TALER_EXCHANGE_KycLongPollTarget lpt;
    270 
    271   /**
    272    * HTTP status code to use for the reply, i.e 200 for "OK".
    273    * Special value UINT_MAX is used to indicate hard errors
    274    * (no reply, return #MHD_NO).
    275    */
    276   unsigned int response_code;
    277   /**
    278    * Output format requested by the client.
    279    */
    280   enum
    281   {
    282     POF_JSON,
    283     POF_TEXT,
    284     POF_PDF
    285   } format;
    286 
    287   /**
    288    * True if @e h_wire was given.
    289    */
    290   bool have_h_wire;
    291 
    292   /**
    293    * True if @e lp_not_etag was given.
    294    */
    295   bool have_lp_not_etag;
    296 
    297   /**
    298    * We're still waiting on the exchange to determine
    299    * the KYC status of our deposit(s).
    300    */
    301   bool return_immediately;
    302 
    303   /**
    304    * Are we currently still iterating over the database and
    305    * thus must not yet respond?
    306    */
    307   bool in_db;
    308 };
    309 
    310 
    311 /**
    312  * Head of DLL.
    313  */
    314 static struct KycContext *kc_head;
    315 
    316 /**
    317  * Tail of DLL.
    318  */
    319 static struct KycContext *kc_tail;
    320 
    321 
    322 void
    323 TMH_force_kyc_resume ()
    324 {
    325   for (struct KycContext *kc = kc_head;
    326        NULL != kc;
    327        kc = kc->next)
    328   {
    329     if (GNUNET_YES == kc->suspended)
    330     {
    331       kc->suspended = GNUNET_SYSERR;
    332       MHD_resume_connection (kc->connection);
    333     }
    334   }
    335 }
    336 
    337 
    338 /**
    339  * Release resources of @a ekr
    340  *
    341  * @param[in] ekr key request data to clean up
    342  */
    343 static void
    344 ekr_cleanup (struct ExchangeKycRequest *ekr)
    345 {
    346   struct KycContext *kc = ekr->kc;
    347 
    348   GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
    349                                kc->exchange_pending_tail,
    350                                ekr);
    351   if (NULL != ekr->fo)
    352   {
    353     TMH_EXCHANGES_keys4exchange_cancel (ekr->fo);
    354     ekr->fo = NULL;
    355   }
    356   json_decref (ekr->pkaa);
    357   json_decref (ekr->jlimits);
    358   if (NULL != ekr->keys)
    359     TALER_EXCHANGE_keys_decref (ekr->keys);
    360   GNUNET_free (ekr->exchange_url);
    361   GNUNET_free (ekr->payto_uri.full_payto);
    362   GNUNET_free (ekr);
    363 }
    364 
    365 
    366 /**
    367  * Custom cleanup routine for a `struct KycContext`.
    368  *
    369  * @param cls the `struct KycContext` to clean up.
    370  */
    371 static void
    372 kyc_context_cleanup (void *cls)
    373 {
    374   struct KycContext *kc = cls;
    375   struct ExchangeKycRequest *ekr;
    376 
    377   while (NULL != (ekr = kc->exchange_pending_head))
    378   {
    379     ekr_cleanup (ekr);
    380   }
    381   if (NULL != kc->eh)
    382   {
    383     TALER_MERCHANTDB_event_listen_cancel (kc->eh);
    384     kc->eh = NULL;
    385   }
    386   if (NULL != kc->response)
    387   {
    388     MHD_destroy_response (kc->response);
    389     kc->response = NULL;
    390   }
    391   GNUNET_CONTAINER_DLL_remove (kc_head,
    392                                kc_tail,
    393                                kc);
    394   json_decref (kc->kycs_data);
    395   GNUNET_free (kc);
    396 }
    397 
    398 
    399 /**
    400  * We have found an exchange in status @a status. Clear any
    401  * long-pollers that wait for us having (or not having) this
    402  * status.
    403  *
    404  * @param[in,out] kc context
    405  * @param status the status we encountered
    406  */
    407 static void
    408 clear_status (struct KycContext *kc,
    409               const char *status)
    410 {
    411   if ( (NULL != kc->lp_status) &&
    412        (0 == strcmp (kc->lp_status,
    413                      status)) )
    414     kc->lp_status = NULL; /* satisfied! */
    415   if ( (NULL != kc->lp_not_status) &&
    416        (0 != strcmp (kc->lp_not_status,
    417                      status) ) )
    418     kc->lp_not_status = NULL; /* satisfied! */
    419 }
    420 
    421 
    422 /**
    423  * Resume the given KYC context and send the final response.  Stores the
    424  * response in the @a kc and signals MHD to resume the connection.  Also
    425  * ensures MHD runs immediately.
    426  *
    427  * @param kc KYC context
    428  */
    429 static void
    430 resume_kyc_with_response (struct KycContext *kc)
    431 {
    432   struct GNUNET_ShortHashCode sh;
    433   bool not_modified;
    434   char *can;
    435 
    436   if ( (! GNUNET_TIME_absolute_is_past (kc->timeout)) &&
    437        ( (NULL != kc->lp_not_status) ||
    438          (NULL != kc->lp_status) ) )
    439   {
    440     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    441                 "Long-poll target status not reached, not returning response yet\n");
    442     if (GNUNET_NO == kc->suspended)
    443     {
    444       MHD_suspend_connection (kc->connection);
    445       kc->suspended = GNUNET_YES;
    446     }
    447     return;
    448   }
    449   can = TALER_JSON_canonicalize (kc->kycs_data);
    450   GNUNET_assert (GNUNET_YES ==
    451                  GNUNET_CRYPTO_hkdf_gnunet (&sh,
    452                                             sizeof (sh),
    453                                             "KYC-SALT",
    454                                             strlen ("KYC-SALT"),
    455                                             can,
    456                                             strlen (can)));
    457   not_modified = kc->have_lp_not_etag &&
    458                  (0 == GNUNET_memcmp (&sh,
    459                                       &kc->lp_not_etag));
    460   if (not_modified &&
    461       (! GNUNET_TIME_absolute_is_past (kc->timeout)) )
    462   {
    463     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    464                 "Status unchanged, not returning response yet\n");
    465     if (GNUNET_NO == kc->suspended)
    466     {
    467       MHD_suspend_connection (kc->connection);
    468       kc->suspended = GNUNET_YES;
    469     }
    470     GNUNET_free (can);
    471     return;
    472   }
    473   {
    474     const char *inm;
    475 
    476     inm = MHD_lookup_connection_value (kc->connection,
    477                                        MHD_GET_ARGUMENT_KIND,
    478                                        MHD_HTTP_HEADER_IF_NONE_MATCH);
    479     if ( (NULL == inm) ||
    480          ('"' != inm[0]) ||
    481          ('"' != inm[strlen (inm) - 1]) ||
    482          (0 != strncmp (inm + 1,
    483                         can,
    484                         strlen (can))) )
    485       not_modified = false; /* must return full response */
    486   }
    487   GNUNET_free (can);
    488   kc->response_code = not_modified
    489     ? MHD_HTTP_NOT_MODIFIED
    490     : MHD_HTTP_OK;
    491   switch (kc->format)
    492   {
    493   case POF_JSON:
    494     kc->response = TALER_MHD_MAKE_JSON_PACK (
    495       GNUNET_JSON_pack_array_incref ("kyc_data",
    496                                      kc->kycs_data));
    497     break;
    498   case POF_TEXT:
    499     {
    500       enum GNUNET_GenericReturnValue ret;
    501       json_t *obj;
    502 
    503       obj = GNUNET_JSON_PACK (
    504         GNUNET_JSON_pack_array_incref ("kyc_data",
    505                                        kc->kycs_data));
    506       ret = TALER_TEMPLATING_build (kc->connection,
    507                                     &kc->response_code,
    508                                     "kyc_text",
    509                                     kc->mi->settings.id,
    510                                     NULL,
    511                                     obj,
    512                                     &kc->response);
    513       json_decref (obj);
    514       if (GNUNET_SYSERR == ret)
    515       {
    516         /* fail hard */
    517         kc->suspended = GNUNET_SYSERR;
    518         MHD_resume_connection (kc->connection);
    519         TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
    520         return;
    521       }
    522       if (GNUNET_OK == ret)
    523       {
    524         TALER_MHD_add_global_headers (kc->response,
    525                                       false);
    526         GNUNET_break (MHD_YES ==
    527                       MHD_add_response_header (kc->response,
    528                                                MHD_HTTP_HEADER_CONTENT_TYPE,
    529                                                "text/plain"));
    530       }
    531     }
    532     break;
    533   case POF_PDF:
    534     // not yet implemented
    535     GNUNET_assert (0);
    536     break;
    537   }
    538   {
    539     char *etag;
    540     char *qetag;
    541 
    542     etag = GNUNET_STRINGS_data_to_string_alloc (&sh,
    543                                                 sizeof (sh));
    544     GNUNET_asprintf (&qetag,
    545                      "\"%s\"",
    546                      etag);
    547     GNUNET_break (MHD_YES ==
    548                   MHD_add_response_header (kc->response,
    549                                            MHD_HTTP_HEADER_ETAG,
    550                                            qetag));
    551     GNUNET_free (qetag);
    552     GNUNET_free (etag);
    553   }
    554   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    555               "Resuming /kyc handling as exchange interaction is done (%u)\n",
    556               MHD_HTTP_OK);
    557   if (GNUNET_YES == kc->suspended)
    558   {
    559     kc->suspended = GNUNET_NO;
    560     MHD_resume_connection (kc->connection);
    561     TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
    562   }
    563 }
    564 
    565 
    566 /**
    567  * Handle a DB event about an update relevant
    568  * for the processing of the kyc request.
    569  *
    570  * @param cls our `struct KycContext`
    571  * @param extra additional event data provided
    572  * @param extra_size number of bytes in @a extra
    573  */
    574 static void
    575 kyc_change_cb (void *cls,
    576                const void *extra,
    577                size_t extra_size)
    578 {
    579   struct KycContext *kc = cls;
    580 
    581   if (GNUNET_YES == kc->suspended)
    582   {
    583     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    584                 "Resuming KYC with gateway timeout\n");
    585     kc->suspended = GNUNET_NO;
    586     MHD_resume_connection (kc->connection);
    587     TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
    588   }
    589 }
    590 
    591 
    592 /**
    593  * Pack the given @a limit into the JSON @a limits array.
    594  *
    595  * @param kc overall request context
    596  * @param limit account limit to pack
    597  * @param[in,out] limits JSON array to extend
    598  */
    599 static void
    600 pack_limit (const struct KycContext *kc,
    601             const struct TALER_EXCHANGE_AccountLimit *limit,
    602             json_t *limits)
    603 {
    604   json_t *jl;
    605 
    606   jl = GNUNET_JSON_PACK (
    607     TALER_JSON_pack_kycte ("operation_type",
    608                            limit->operation_type),
    609     GNUNET_JSON_pack_bool (
    610       "disallowed",
    611       GNUNET_TIME_relative_is_zero (limit->timeframe) ||
    612       TALER_amount_is_zero (&limit->threshold)),
    613     (POF_TEXT == kc->format)
    614     ? GNUNET_JSON_pack_string ("interval",
    615                                GNUNET_TIME_relative2s (limit->timeframe,
    616                                                        true))
    617     : GNUNET_JSON_pack_time_rel ("timeframe",
    618                                  limit->timeframe),
    619     TALER_JSON_pack_amount ("threshold",
    620                             &limit->threshold),
    621     GNUNET_JSON_pack_bool ("soft_limit",
    622                            limit->soft_limit)
    623     );
    624   GNUNET_assert (0 ==
    625                  json_array_append_new (limits,
    626                                         jl));
    627 }
    628 
    629 
    630 /**
    631  * Return JSON array with AccountLimit objects giving
    632  * the current limits for this exchange.
    633  *
    634  * @param[in,out] ekr overall request context
    635  */
    636 static json_t *
    637 get_exchange_limits (
    638   struct ExchangeKycRequest *ekr)
    639 {
    640   const struct TALER_EXCHANGE_Keys *keys = ekr->keys;
    641   json_t *limits;
    642 
    643   if (NULL != ekr->jlimits)
    644   {
    645     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    646                 "Returning custom KYC limits\n");
    647     return json_incref (ekr->jlimits);
    648   }
    649   if (NULL == keys)
    650   {
    651     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    652                 "No keys, thus no default KYC limits known\n");
    653     return NULL;
    654   }
    655   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    656               "Returning default KYC limits (%u/%u)\n",
    657               keys->hard_limits_length,
    658               keys->zero_limits_length);
    659   limits = json_array ();
    660   GNUNET_assert (NULL != limits);
    661   for (unsigned int i = 0; i<keys->hard_limits_length; i++)
    662   {
    663     const struct TALER_EXCHANGE_AccountLimit *limit
    664       = &keys->hard_limits[i];
    665 
    666     pack_limit (ekr->kc,
    667                 limit,
    668                 limits);
    669   }
    670   for (unsigned int i = 0; i<keys->zero_limits_length; i++)
    671   {
    672     const struct TALER_EXCHANGE_ZeroLimitedOperation *zlimit
    673       = &keys->zero_limits[i];
    674     json_t *jl;
    675     struct TALER_Amount zero;
    676 
    677     GNUNET_assert (GNUNET_OK ==
    678                    TALER_amount_set_zero (keys->currency,
    679                                           &zero));
    680     jl = GNUNET_JSON_PACK (
    681       TALER_JSON_pack_kycte ("operation_type",
    682                              zlimit->operation_type),
    683       GNUNET_JSON_pack_bool (
    684         "disallowed",
    685         true),
    686       (POF_TEXT == ekr->kc->format)
    687       ? GNUNET_JSON_pack_string (
    688         "interval",
    689         GNUNET_TIME_relative2s (GNUNET_TIME_UNIT_ZERO,
    690                                 true))
    691       : GNUNET_JSON_pack_time_rel ("timeframe",
    692                                    GNUNET_TIME_UNIT_ZERO),
    693       TALER_JSON_pack_amount ("threshold",
    694                               &zero),
    695       GNUNET_JSON_pack_bool ("soft_limit",
    696                              true)
    697       );
    698     GNUNET_assert (0 ==
    699                    json_array_append_new (limits,
    700                                           jl));
    701   }
    702   return limits;
    703 }
    704 
    705 
    706 /**
    707  * Maps @a ekr to a status code for clients to interpret the
    708  * overall result.
    709  *
    710  * @param ekr request summary
    711  * @return status of the KYC state as a string
    712  */
    713 static const char *
    714 map_to_status (const struct ExchangeKycRequest *ekr)
    715 {
    716   if (ekr->no_keys)
    717   {
    718     return "no-exchange-keys";
    719   }
    720   if (TALER_EC_MERCHANT_PRIVATE_ACCOUNT_NOT_ELIGIBLE_FOR_EXCHANGE ==
    721       ekr->last_ec)
    722     return "unsupported-account";
    723   if (ekr->kyc_ok)
    724   {
    725     if (NULL != ekr->jlimits)
    726     {
    727       size_t off;
    728       json_t *limit;
    729       json_array_foreach (ekr->jlimits, off, limit)
    730       {
    731         struct TALER_Amount threshold;
    732         enum TALER_KYCLOGIC_KycTriggerEvent operation_type;
    733         bool soft = false;
    734         struct GNUNET_JSON_Specification spec[] = {
    735           TALER_JSON_spec_kycte ("operation_type",
    736                                  &operation_type),
    737           TALER_JSON_spec_amount_any ("threshold",
    738                                       &threshold),
    739           GNUNET_JSON_spec_mark_optional (
    740             GNUNET_JSON_spec_bool ("soft_limit",
    741                                    &soft),
    742             NULL),
    743           GNUNET_JSON_spec_end ()
    744         };
    745 
    746         if (GNUNET_OK !=
    747             GNUNET_JSON_parse (limit,
    748                                spec,
    749                                NULL, NULL))
    750         {
    751           GNUNET_break (0);
    752           return "merchant-internal-error";
    753         }
    754         if (! TALER_amount_is_zero (&threshold))
    755           continue; /* only care about zero-limits */
    756         if (! soft)
    757           continue; /* only care about soft limits */
    758         if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
    759              (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) ||
    760              (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) )
    761         {
    762           if (! ekr->auth_ok)
    763           {
    764             if (ekr->kyc_auth_conflict)
    765               return "kyc-wire-impossible";
    766             return "kyc-wire-required";
    767           }
    768           return "kyc-required";
    769         }
    770       }
    771     }
    772     if (NULL == ekr->jlimits)
    773     {
    774       /* check default limits */
    775       const struct TALER_EXCHANGE_Keys *keys = ekr->keys;
    776 
    777       for (unsigned int i = 0; i < keys->zero_limits_length; i++)
    778       {
    779         enum TALER_KYCLOGIC_KycTriggerEvent operation_type
    780           = keys->zero_limits[i].operation_type;
    781 
    782         if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
    783              (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) ||
    784              (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) )
    785         {
    786           if (! ekr->auth_ok)
    787           {
    788             if (ekr->kyc_auth_conflict)
    789               return "kyc-wire-impossible";
    790             return "kyc-wire-required";
    791           }
    792           return "kyc-required";
    793         }
    794       }
    795     }
    796     return "ready";
    797   }
    798   if (! ekr->auth_ok)
    799   {
    800     if (ekr->kyc_auth_conflict)
    801       return "kyc-wire-impossible";
    802     return "kyc-wire-required";
    803   }
    804   if (ekr->in_aml_review)
    805     return "awaiting-aml-review";
    806   switch (ekr->last_http_status)
    807   {
    808   case 0:
    809     return "exchange-unreachable";
    810   case MHD_HTTP_OK:
    811     /* then we should have kyc_ok */
    812     GNUNET_break (0);
    813     return NULL;
    814   case MHD_HTTP_ACCEPTED:
    815     /* Then KYC is really what  is needed */
    816     return "kyc-required";
    817   case MHD_HTTP_NO_CONTENT:
    818     /* then we should have had kyc_ok! */
    819     GNUNET_break (0);
    820     return NULL;
    821   case MHD_HTTP_FORBIDDEN:
    822     /* then we should have had ! auth_ok */
    823     GNUNET_break (0);
    824     return NULL;
    825   case MHD_HTTP_NOT_FOUND:
    826     /* then we should have had ! auth_ok */
    827     GNUNET_break (0);
    828     return NULL;
    829   case MHD_HTTP_CONFLICT:
    830     /* then we should have had ! auth_ok */
    831     GNUNET_break (0);
    832     return NULL;
    833   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    834     return "exchange-internal-error";
    835   case MHD_HTTP_GATEWAY_TIMEOUT:
    836     return "exchange-gateway-timeout";
    837   default:
    838     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    839                 "Exchange responded with unexpected HTTP status %u to /kyc-check request!\n",
    840                 ekr->last_http_status);
    841     break;
    842   }
    843   return "exchange-status-invalid";
    844 }
    845 
    846 
    847 /**
    848  * Take data from @a ekr to expand our response.
    849  *
    850  * @param ekr exchange we are done inspecting
    851  */
    852 static void
    853 ekr_expand_response (struct ExchangeKycRequest *ekr)
    854 {
    855   const struct KycContext *kc = ekr->kc;
    856   struct TMH_Exchange *e = TMH_EXCHANGES_lookup_exchange (ekr->exchange_url);
    857   const char *status;
    858   const char *q;
    859   char *short_account;
    860 
    861   GNUNET_assert (NULL != e);
    862   status = map_to_status (ekr);
    863   if (NULL == status)
    864   {
    865     GNUNET_break (0);
    866     status = "logic-bug";
    867   }
    868   clear_status (ekr->kc,
    869                 status);
    870   q = strchr (ekr->payto_uri.full_payto,
    871               '?');
    872   if (NULL == q)
    873     short_account = GNUNET_strdup (ekr->payto_uri.full_payto);
    874   else
    875     short_account = GNUNET_strndup (ekr->payto_uri.full_payto,
    876                                     q - ekr->payto_uri.full_payto);
    877   GNUNET_assert (
    878     0 ==
    879     json_array_append_new (
    880       ekr->kc->kycs_data,
    881       GNUNET_JSON_PACK (
    882         (POF_TEXT == kc->format)
    883         ? GNUNET_JSON_pack_string (
    884           "short_payto_uri",
    885           short_account)
    886         : TALER_JSON_pack_full_payto (
    887           "payto_uri",
    888           ekr->payto_uri),
    889         GNUNET_JSON_pack_data_auto (
    890           "h_wire",
    891           &ekr->h_wire),
    892         GNUNET_JSON_pack_string (
    893           "status",
    894           status),
    895         GNUNET_JSON_pack_string (
    896           "exchange_url",
    897           ekr->exchange_url),
    898         GNUNET_JSON_pack_string (
    899           "exchange_currency",
    900           TMH_EXCHANGES_get_currency (e)),
    901         GNUNET_JSON_pack_bool ("no_keys",
    902                                ekr->no_keys),
    903         GNUNET_JSON_pack_bool ("auth_conflict",
    904                                ekr->kyc_auth_conflict),
    905         GNUNET_JSON_pack_uint64 ("exchange_http_status",
    906                                  ekr->last_http_status),
    907         (TALER_EC_NONE == ekr->last_ec)
    908         ? GNUNET_JSON_pack_allow_null (
    909           GNUNET_JSON_pack_string (
    910             "dummy",
    911             NULL))
    912         : GNUNET_JSON_pack_uint64 ("exchange_code",
    913                                    ekr->last_ec),
    914         ekr->auth_ok
    915         ? GNUNET_JSON_pack_data_auto (
    916           "access_token",
    917           &ekr->access_token)
    918         : GNUNET_JSON_pack_allow_null (
    919           GNUNET_JSON_pack_string (
    920             "dummy",
    921             NULL)),
    922         GNUNET_JSON_pack_allow_null (
    923           GNUNET_JSON_pack_array_steal (
    924             "limits",
    925             get_exchange_limits (ekr))),
    926         GNUNET_JSON_pack_allow_null (
    927           GNUNET_JSON_pack_array_incref ("payto_kycauths",
    928                                          ekr->pkaa))
    929         )));
    930   GNUNET_free (short_account);
    931 }
    932 
    933 
    934 /**
    935  * We are done with asynchronous processing, generate the
    936  * response for the @e kc.
    937  *
    938  * @param[in,out] kc KYC context to respond for
    939  */
    940 static void
    941 kc_respond (struct KycContext *kc)
    942 {
    943   if ( (! kc->return_immediately) &&
    944        (! GNUNET_TIME_absolute_is_past (kc->timeout)) )
    945   {
    946     if (GNUNET_NO == kc->suspended)
    947     {
    948       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    949                   "Suspending: long poll target %d not reached\n",
    950                   kc->lpt);
    951       MHD_suspend_connection (kc->connection);
    952       kc->suspended = GNUNET_YES;
    953     }
    954     else
    955     {
    956       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    957                   "Remaining suspended: long poll target %d not reached\n",
    958                   kc->lpt);
    959     }
    960     return;
    961   }
    962   /* All exchange requests done, create final
    963      big response from cumulated replies */
    964   resume_kyc_with_response (kc);
    965 }
    966 
    967 
    968 /**
    969  * We are done with the KYC request @a ekr.  Remove it from the work list and
    970  * check if we are done overall.
    971  *
    972  * @param[in] ekr key request that is done (and will be freed)
    973  */
    974 static void
    975 ekr_finished (struct ExchangeKycRequest *ekr)
    976 {
    977   struct KycContext *kc = ekr->kc;
    978 
    979   ekr_expand_response (ekr);
    980   ekr_cleanup (ekr);
    981   if (NULL != kc->exchange_pending_head)
    982     return; /* wait for more */
    983   if (kc->in_db)
    984     return;
    985   kc_respond (kc);
    986 }
    987 
    988 
    989 /**
    990  * Figure out which exchange accounts from @a keys could
    991  * be used for a KYC auth wire transfer from the account
    992  * that @a ekr is checking. Will set the "pkaa" array
    993  * in @a ekr.
    994  *
    995  * @param[in,out] ekr request we are processing
    996  */
    997 static void
    998 determine_eligible_accounts (
    999   struct ExchangeKycRequest *ekr)
   1000 {
   1001   struct KycContext *kc = ekr->kc;
   1002   const struct TALER_EXCHANGE_Keys *keys = ekr->keys;
   1003   struct TALER_Amount kyc_amount;
   1004   char *merchant_pub_str;
   1005   struct TALER_NormalizedPayto np;
   1006 
   1007   ekr->pkaa = json_array ();
   1008   GNUNET_assert (NULL != ekr->pkaa);
   1009   {
   1010     const struct TALER_EXCHANGE_GlobalFee *gf;
   1011 
   1012     gf = TALER_EXCHANGE_get_global_fee (keys,
   1013                                         GNUNET_TIME_timestamp_get ());
   1014     if (NULL == gf)
   1015     {
   1016       GNUNET_assert (GNUNET_OK ==
   1017                      TALER_amount_set_zero (keys->currency,
   1018                                             &kyc_amount));
   1019     }
   1020     else
   1021     {
   1022       /* FIXME-#9427: history fee should be globally renamed to KYC fee... */
   1023       kyc_amount = gf->fees.history;
   1024     }
   1025   }
   1026 
   1027   merchant_pub_str
   1028     = GNUNET_STRINGS_data_to_string_alloc (
   1029         &kc->mi->merchant_pub,
   1030         sizeof (kc->mi->merchant_pub));
   1031   /* For all accounts of the exchange */
   1032   np = TALER_payto_normalize (ekr->payto_uri);
   1033   for (unsigned int i = 0; i<keys->accounts_len; i++)
   1034   {
   1035     const struct TALER_EXCHANGE_WireAccount *account
   1036       = &keys->accounts[i];
   1037 
   1038     /* KYC auth transfers are never supported with conversion */
   1039     if (NULL != account->conversion_url)
   1040       continue;
   1041     /* filter by source account by credit_restrictions */
   1042     if (GNUNET_YES !=
   1043         TALER_EXCHANGE_test_account_allowed (account,
   1044                                              true, /* credit */
   1045                                              np))
   1046       continue;
   1047     /* exchange account is allowed, add it */
   1048     {
   1049       const char *exchange_account_payto
   1050         = account->fpayto_uri.full_payto;
   1051       char *payto_kycauth;
   1052 
   1053       if (TALER_amount_is_zero (&kyc_amount))
   1054         GNUNET_asprintf (&payto_kycauth,
   1055                          "%s%cmessage=KYC:%s",
   1056                          exchange_account_payto,
   1057                          (NULL == strchr (exchange_account_payto,
   1058                                           '?'))
   1059                          ? '?'
   1060                          : '&',
   1061                          merchant_pub_str);
   1062       else
   1063         GNUNET_asprintf (&payto_kycauth,
   1064                          "%s%camount=%s&message=KYC:%s",
   1065                          exchange_account_payto,
   1066                          (NULL == strchr (exchange_account_payto,
   1067                                           '?'))
   1068                          ? '?'
   1069                          : '&',
   1070                          TALER_amount2s (&kyc_amount),
   1071                          merchant_pub_str);
   1072       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1073                   "Found account %s where KYC auth is possible\n",
   1074                   payto_kycauth);
   1075       GNUNET_assert (0 ==
   1076                      json_array_append_new (ekr->pkaa,
   1077                                             json_string (payto_kycauth)));
   1078       GNUNET_free (payto_kycauth);
   1079     }
   1080   }
   1081   GNUNET_free (np.normalized_payto);
   1082   GNUNET_free (merchant_pub_str);
   1083 }
   1084 
   1085 
   1086 /**
   1087  * Function called with the result of a #TMH_EXCHANGES_keys4exchange()
   1088  * operation.  Runs the KYC check against the exchange.
   1089  *
   1090  * @param cls closure with our `struct ExchangeKycRequest *`
   1091  * @param keys keys of the exchange context
   1092  * @param exchange representation of the exchange
   1093  */
   1094 static void
   1095 kyc_with_exchange (void *cls,
   1096                    struct TALER_EXCHANGE_Keys *keys,
   1097                    struct TMH_Exchange *exchange)
   1098 {
   1099   struct ExchangeKycRequest *ekr = cls;
   1100 
   1101   (void) exchange;
   1102   ekr->fo = NULL;
   1103   if (NULL == keys)
   1104   {
   1105     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1106                 "Failed to download `%skeys`\n",
   1107                 ekr->exchange_url);
   1108     ekr->no_keys = true;
   1109     ekr_finished (ekr);
   1110     return;
   1111   }
   1112   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1113               "Got /keys for `%s'\n",
   1114               ekr->exchange_url);
   1115   ekr->keys = TALER_EXCHANGE_keys_incref (keys);
   1116   if (! ekr->auth_ok)
   1117   {
   1118     determine_eligible_accounts (ekr);
   1119     if (0 == json_array_size (ekr->pkaa))
   1120     {
   1121       /* No KYC auth wire transfers are possible to this exchange from
   1122          our merchant bank account, so we cannot use this account with
   1123          this exchange if it has any KYC requirements! */
   1124       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1125                   "KYC auth to `%s' impossible for merchant account `%s'\n",
   1126                   ekr->exchange_url,
   1127                   ekr->payto_uri.full_payto);
   1128       ekr->kyc_auth_conflict = true;
   1129     }
   1130   }
   1131   ekr_finished (ekr);
   1132 }
   1133 
   1134 
   1135 /**
   1136  * Closure for add_unreachable_status().
   1137  */
   1138 struct UnreachableContext
   1139 {
   1140   /**
   1141    * Where we are building the response.
   1142    */
   1143   struct KycContext *kc;
   1144 
   1145   /**
   1146    * Pointer to our account hash.
   1147    */
   1148   const struct TALER_MerchantWireHashP *h_wire;
   1149 
   1150   /**
   1151    * Bank account for which we have no status from any exchange.
   1152    */
   1153   struct TALER_FullPayto payto_uri;
   1154 
   1155 };
   1156 
   1157 /**
   1158  * Add all trusted exchanges with "unknown" status for the
   1159  * bank account given in the context.
   1160  *
   1161  * @param cls a `struct UnreachableContext`
   1162  * @param url base URL of the exchange
   1163  * @param exchange internal handle for the exchange
   1164  */
   1165 static void
   1166 add_unreachable_status (void *cls,
   1167                         const char *url,
   1168                         const struct TMH_Exchange *exchange)
   1169 {
   1170   struct UnreachableContext *uc = cls;
   1171   struct KycContext *kc = uc->kc;
   1172 
   1173   clear_status (kc,
   1174                 "exchange-unreachable");
   1175   GNUNET_assert (
   1176     0 ==
   1177     json_array_append_new (
   1178       kc->kycs_data,
   1179       GNUNET_JSON_PACK (
   1180         TALER_JSON_pack_full_payto (
   1181           "payto_uri",
   1182           uc->payto_uri),
   1183         GNUNET_JSON_pack_data_auto (
   1184           "h_wire",
   1185           uc->h_wire),
   1186         GNUNET_JSON_pack_string (
   1187           "exchange_currency",
   1188           TMH_EXCHANGES_get_currency (exchange)),
   1189         GNUNET_JSON_pack_string (
   1190           "status",
   1191           "exchange-unreachable"),
   1192         GNUNET_JSON_pack_string (
   1193           "exchange_url",
   1194           url),
   1195         GNUNET_JSON_pack_bool ("no_keys",
   1196                                true),
   1197         GNUNET_JSON_pack_bool ("auth_conflict",
   1198                                false),
   1199         GNUNET_JSON_pack_uint64 ("exchange_http_status",
   1200                                  0)
   1201         )));
   1202 
   1203 }
   1204 
   1205 
   1206 /**
   1207  * Function called from account_kyc_get_status() with KYC status information
   1208  * for this merchant.
   1209  *
   1210  * @param cls our `struct KycContext *`
   1211  * @param h_wire hash of the wire account
   1212  * @param payto_uri payto:// URI of the merchant's bank account
   1213  * @param exchange_url base URL of the exchange for which this is a status
   1214  * @param last_check when did we last get an update on our KYC status from the exchange
   1215  * @param kyc_ok true if we satisfied the KYC requirements
   1216  * @param access_token access token for the KYC SPA, NULL if we cannot access it yet (need KYC auth wire transfer)
   1217  * @param last_http_status last HTTP status from /kyc-check
   1218  * @param last_ec last Taler error code from /kyc-check
   1219  * @param in_aml_review true if the account is pending review
   1220  * @param jlimits JSON array of applicable AccountLimits, or NULL if unknown (like defaults apply)
   1221  */
   1222 static void
   1223 kyc_status_cb (
   1224   void *cls,
   1225   const struct TALER_MerchantWireHashP *h_wire,
   1226   struct TALER_FullPayto payto_uri,
   1227   const char *exchange_url,
   1228   struct GNUNET_TIME_Timestamp last_check,
   1229   bool kyc_ok,
   1230   const struct TALER_AccountAccessTokenP *access_token,
   1231   unsigned int last_http_status,
   1232   enum TALER_ErrorCode last_ec,
   1233   bool in_aml_review,
   1234   const json_t *jlimits)
   1235 {
   1236   struct KycContext *kc = cls;
   1237   struct ExchangeKycRequest *ekr;
   1238 
   1239   if (NULL == exchange_url)
   1240   {
   1241     struct UnreachableContext uc = {
   1242       .kc = kc,
   1243       .h_wire = h_wire,
   1244       .payto_uri = payto_uri
   1245     };
   1246 
   1247     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1248                 "Account has unknown KYC status for all exchanges.\n");
   1249     TMH_exchange_get_trusted (&add_unreachable_status,
   1250                               &uc);
   1251     return;
   1252   }
   1253   if (! TMH_EXCHANGES_check_trusted (exchange_url))
   1254   {
   1255     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1256                 "Skipping exchange `%s': not trusted\n",
   1257                 exchange_url);
   1258     return;
   1259   }
   1260   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1261               "KYC status for `%s' at `%s' is %u/%s/%s/%s\n",
   1262               payto_uri.full_payto,
   1263               exchange_url,
   1264               last_http_status,
   1265               kyc_ok ? "KYC OK" : "KYC NEEDED",
   1266               in_aml_review ? "IN AML REVIEW" : "NO AML REVIEW",
   1267               NULL == jlimits ? "DEFAULT LIMITS" : "CUSTOM LIMITS");
   1268   switch (kc->lpt)
   1269   {
   1270   case TALER_EXCHANGE_KLPT_NONE:
   1271     break;
   1272   case TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER:
   1273     if (NULL != access_token)
   1274       kc->return_immediately = true;
   1275     break;
   1276   case TALER_EXCHANGE_KLPT_INVESTIGATION_DONE:
   1277     if (! in_aml_review)
   1278       kc->return_immediately = true;
   1279     break;
   1280   case TALER_EXCHANGE_KLPT_KYC_OK:
   1281     if (kyc_ok)
   1282       kc->return_immediately = true;
   1283     break;
   1284   }
   1285   ekr = GNUNET_new (struct ExchangeKycRequest);
   1286   GNUNET_CONTAINER_DLL_insert (kc->exchange_pending_head,
   1287                                kc->exchange_pending_tail,
   1288                                ekr);
   1289   ekr->last_http_status = last_http_status;
   1290   ekr->last_ec = last_ec;
   1291   if (NULL != jlimits)
   1292     ekr->jlimits = json_incref ((json_t *) jlimits);
   1293   ekr->h_wire = *h_wire;
   1294   ekr->exchange_url = GNUNET_strdup (exchange_url);
   1295   ekr->payto_uri.full_payto
   1296     = GNUNET_strdup (payto_uri.full_payto);
   1297   ekr->last_check = last_check;
   1298   ekr->kyc_ok = kyc_ok;
   1299   ekr->kc = kc;
   1300   ekr->in_aml_review = in_aml_review;
   1301   ekr->auth_ok = (NULL != access_token);
   1302   if ( (! ekr->auth_ok) ||
   1303        (NULL == ekr->jlimits) )
   1304   {
   1305     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1306                 "Awaiting /keys from `%s'\n",
   1307                 exchange_url);
   1308 
   1309     /* Figure out wire transfer instructions */
   1310     if (GNUNET_NO == kc->suspended)
   1311     {
   1312       MHD_suspend_connection (kc->connection);
   1313       kc->suspended = GNUNET_YES;
   1314     }
   1315     ekr->fo = TMH_EXCHANGES_keys4exchange (
   1316       exchange_url,
   1317       false,
   1318       &kyc_with_exchange,
   1319       ekr);
   1320     if (NULL == ekr->fo)
   1321     {
   1322       GNUNET_break (0);
   1323       ekr_finished (ekr);
   1324       return;
   1325     }
   1326     return;
   1327   }
   1328   ekr->access_token = *access_token;
   1329   ekr_finished (ekr);
   1330 }
   1331 
   1332 
   1333 /**
   1334  * Check the KYC status of an instance.
   1335  *
   1336  * @param mi instance to check KYC status of
   1337  * @param connection the MHD connection to handle
   1338  * @param[in,out] hc context with further information about the request
   1339  * @return MHD result code
   1340  */
   1341 static enum MHD_Result
   1342 get_instances_ID_kyc (
   1343   struct TMH_MerchantInstance *mi,
   1344   struct MHD_Connection *connection,
   1345   struct TMH_HandlerContext *hc)
   1346 {
   1347   struct KycContext *kc = hc->ctx;
   1348 
   1349   if (NULL == kc)
   1350   {
   1351     kc = GNUNET_new (struct KycContext);
   1352     kc->mi = mi;
   1353     hc->ctx = kc;
   1354     hc->cc = &kyc_context_cleanup;
   1355     GNUNET_CONTAINER_DLL_insert (kc_head,
   1356                                  kc_tail,
   1357                                  kc);
   1358     kc->connection = connection;
   1359     kc->hc = hc;
   1360     kc->kycs_data = json_array ();
   1361     GNUNET_assert (NULL != kc->kycs_data);
   1362     TALER_MHD_parse_request_timeout (connection,
   1363                                      &kc->timeout);
   1364     {
   1365       uint64_t num = 0;
   1366       int val;
   1367 
   1368       TALER_MHD_parse_request_number (connection,
   1369                                       "lpt",
   1370                                       &num);
   1371       val = (int) num;
   1372       if ( (val < 0) ||
   1373            (val > TALER_EXCHANGE_KLPT_MAX) )
   1374       {
   1375         /* Protocol violation, but we can be graceful and
   1376            just ignore the long polling! */
   1377         GNUNET_break_op (0);
   1378         val = TALER_EXCHANGE_KLPT_NONE;
   1379       }
   1380       kc->lpt = (enum TALER_EXCHANGE_KycLongPollTarget) val;
   1381     }
   1382     kc->return_immediately
   1383       = (TALER_EXCHANGE_KLPT_NONE == kc->lpt);
   1384     /* process 'exchange_url' argument */
   1385     kc->exchange_url = MHD_lookup_connection_value (
   1386       connection,
   1387       MHD_GET_ARGUMENT_KIND,
   1388       "exchange_url");
   1389     if ( (NULL != kc->exchange_url) &&
   1390          ( (! TALER_url_valid_charset (kc->exchange_url)) ||
   1391            (! TALER_is_web_url (kc->exchange_url)) ) )
   1392     {
   1393       GNUNET_break_op (0);
   1394       return TALER_MHD_reply_with_error (
   1395         connection,
   1396         MHD_HTTP_BAD_REQUEST,
   1397         TALER_EC_GENERIC_PARAMETER_MALFORMED,
   1398         "exchange_url must be a valid HTTP(s) URL");
   1399     }
   1400     kc->lp_status = MHD_lookup_connection_value (
   1401       connection,
   1402       MHD_GET_ARGUMENT_KIND,
   1403       "lp_status");
   1404     kc->lp_not_status = MHD_lookup_connection_value (
   1405       connection,
   1406       MHD_GET_ARGUMENT_KIND,
   1407       "lp_not_status");
   1408     TALER_MHD_parse_request_arg_auto (connection,
   1409                                       "h_wire",
   1410                                       &kc->h_wire,
   1411                                       kc->have_h_wire);
   1412     TALER_MHD_parse_request_arg_auto (connection,
   1413                                       "lp_not_etag",
   1414                                       &kc->lp_not_etag,
   1415                                       kc->have_lp_not_etag);
   1416 
   1417     /* Determine desired output format from Accept header */
   1418     {
   1419       const char *mime;
   1420 
   1421       mime = MHD_lookup_connection_value (connection,
   1422                                           MHD_HEADER_KIND,
   1423                                           MHD_HTTP_HEADER_ACCEPT);
   1424       if (NULL == mime)
   1425         mime = "application/json";
   1426       if (0 == strcmp (mime,
   1427                        "*/*"))
   1428         mime = "application/json";
   1429       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1430                   "KYC status requested for format %s\n",
   1431                   mime);
   1432       if (0 == strcmp (mime,
   1433                        "application/json"))
   1434       {
   1435         kc->format = POF_JSON;
   1436       }
   1437       else if (0 == strcmp (mime,
   1438                             "text/plain"))
   1439       {
   1440         kc->format = POF_TEXT;
   1441       }
   1442 #if FUTURE
   1443       else if (0 == strcmp (mime,
   1444                             "application/pdf"))
   1445       {
   1446         kc->format = POF_PDF;
   1447       }
   1448 #endif
   1449       else
   1450       {
   1451         GNUNET_break_op (0);
   1452         return TALER_MHD_REPLY_JSON_PACK (
   1453           connection,
   1454           MHD_HTTP_NOT_ACCEPTABLE,
   1455           GNUNET_JSON_pack_string ("hint",
   1456                                    mime));
   1457       }
   1458     }
   1459 
   1460     if (! GNUNET_TIME_absolute_is_past (kc->timeout))
   1461     {
   1462       if (kc->have_h_wire)
   1463       {
   1464         struct TALER_MERCHANTDB_MerchantKycStatusChangeEventP ev = {
   1465           .header.size = htons (sizeof (ev)),
   1466           .header.type = htons (
   1467             TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_STATUS_CHANGED
   1468             ),
   1469           .h_wire = kc->h_wire
   1470         };
   1471 
   1472         kc->eh = TALER_MERCHANTDB_event_listen (
   1473           TMH_db,
   1474           &ev.header,
   1475           GNUNET_TIME_absolute_get_remaining (kc->timeout),
   1476           &kyc_change_cb,
   1477           kc);
   1478       }
   1479       else
   1480       {
   1481         struct GNUNET_DB_EventHeaderP hdr = {
   1482           .size = htons (sizeof (hdr)),
   1483           .type = htons (TALER_DBEVENT_MERCHANT_KYC_STATUS_CHANGED)
   1484         };
   1485 
   1486         kc->eh = TALER_MERCHANTDB_event_listen (
   1487           TMH_db,
   1488           &hdr,
   1489           GNUNET_TIME_absolute_get_remaining (kc->timeout),
   1490           &kyc_change_cb,
   1491           kc);
   1492       }
   1493     } /* end register LISTEN hooks */
   1494   } /* end 1st time initialization */
   1495 
   1496   if (GNUNET_SYSERR == kc->suspended)
   1497     return MHD_NO; /* during shutdown, we don't generate any more replies */
   1498   GNUNET_assert (GNUNET_NO == kc->suspended);
   1499 
   1500   if (NULL != kc->response)
   1501     return MHD_queue_response (connection,
   1502                                kc->response_code,
   1503                                kc->response);
   1504 
   1505   /* Check our database */
   1506   {
   1507     enum GNUNET_DB_QueryStatus qs;
   1508 
   1509     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1510                 "Checking KYC status for %s (%d/%s)\n",
   1511                 mi->settings.id,
   1512                 kc->have_h_wire,
   1513                 kc->exchange_url);
   1514     /* We may run repeatedly due to long-polling; clear data
   1515        from previous runs first */
   1516     GNUNET_break (0 ==
   1517                   json_array_clear (kc->kycs_data));
   1518     kc->in_db = true;
   1519     qs = TALER_MERCHANTDB_account_kyc_get_status (
   1520       TMH_db,
   1521       mi->settings.id,
   1522       kc->have_h_wire
   1523       ? &kc->h_wire
   1524       : NULL,
   1525       kc->exchange_url,
   1526       &kyc_status_cb,
   1527       kc);
   1528     kc->in_db = false;
   1529     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1530                 "account_kyc_get_status returned %d records\n",
   1531                 (int) qs);
   1532     switch (qs)
   1533     {
   1534     case GNUNET_DB_STATUS_HARD_ERROR:
   1535     case GNUNET_DB_STATUS_SOFT_ERROR:
   1536       /* Database error */
   1537       GNUNET_break (0);
   1538       if (GNUNET_YES == kc->suspended)
   1539       {
   1540         /* must have suspended before DB error, resume! */
   1541         MHD_resume_connection (connection);
   1542         kc->suspended = GNUNET_NO;
   1543       }
   1544       return TALER_MHD_reply_with_ec (
   1545         connection,
   1546         TALER_EC_GENERIC_DB_FETCH_FAILED,
   1547         "account_kyc_get_status");
   1548     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1549       {
   1550         /* We use an Etag of all zeros for the 204 status code */
   1551         static struct GNUNET_ShortHashCode zero_etag;
   1552 
   1553         /* no matching accounts, could not have suspended */
   1554         GNUNET_assert (GNUNET_NO == kc->suspended);
   1555         if (kc->have_lp_not_etag &&
   1556             (0 == GNUNET_memcmp (&zero_etag,
   1557                                  &kc->lp_not_etag)) &&
   1558             (! GNUNET_TIME_absolute_is_past (kc->timeout)) )
   1559         {
   1560           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1561                       "No matching accounts, suspending to wait for this to change\n");
   1562           MHD_suspend_connection (kc->connection);
   1563           kc->suspended = GNUNET_YES;
   1564           return MHD_YES;
   1565         }
   1566         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1567                     "No matching accounts, returning empty response\n");
   1568         kc->response_code = MHD_HTTP_NO_CONTENT;
   1569         kc->response = MHD_create_response_from_buffer_static (0,
   1570                                                                NULL);
   1571         TALER_MHD_add_global_headers (kc->response,
   1572                                       false);
   1573         {
   1574           char *etag;
   1575 
   1576           etag = GNUNET_STRINGS_data_to_string_alloc (&zero_etag,
   1577                                                       sizeof (zero_etag));
   1578           GNUNET_break (MHD_YES ==
   1579                         MHD_add_response_header (kc->response,
   1580                                                  MHD_HTTP_HEADER_ETAG,
   1581                                                  etag));
   1582           GNUNET_free (etag);
   1583         }
   1584         return MHD_queue_response (connection,
   1585                                    kc->response_code,
   1586                                    kc->response);
   1587       }
   1588     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1589       break;
   1590     } /* end switch (qs) */
   1591   }
   1592 
   1593   /* normal case, but maybe no async activity? In this case,
   1594      respond immediately */
   1595   if (NULL == kc->exchange_pending_head)
   1596   {
   1597     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1598                 "No asynchronous activity, responding now\n");
   1599     kc_respond (kc);
   1600   }
   1601   if (GNUNET_YES == kc->suspended)
   1602   {
   1603     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1604                 "Request handling suspended, waiting for KYC status change\n");
   1605     return MHD_YES;
   1606   }
   1607 
   1608   /* Should have generated a response */
   1609   GNUNET_break (NULL != kc->response);
   1610   return MHD_queue_response (connection,
   1611                              kc->response_code,
   1612                              kc->response);
   1613 }
   1614 
   1615 
   1616 enum MHD_Result
   1617 TMH_private_get_instances_ID_kyc (
   1618   const struct TMH_RequestHandler *rh,
   1619   struct MHD_Connection *connection,
   1620   struct TMH_HandlerContext *hc)
   1621 {
   1622   struct TMH_MerchantInstance *mi = hc->instance;
   1623 
   1624   (void) rh;
   1625   return get_instances_ID_kyc (mi,
   1626                                connection,
   1627                                hc);
   1628 }
   1629 
   1630 
   1631 enum MHD_Result
   1632 TMH_private_get_instances_default_ID_kyc (
   1633   const struct TMH_RequestHandler *rh,
   1634   struct MHD_Connection *connection,
   1635   struct TMH_HandlerContext *hc)
   1636 {
   1637   struct TMH_MerchantInstance *mi;
   1638 
   1639   (void) rh;
   1640   mi = TMH_lookup_instance (hc->infix);
   1641   if (NULL == mi)
   1642   {
   1643     return TALER_MHD_reply_with_error (
   1644       connection,
   1645       MHD_HTTP_NOT_FOUND,
   1646       TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN,
   1647       hc->infix);
   1648   }
   1649   return get_instances_ID_kyc (mi,
   1650                                connection,
   1651                                hc);
   1652 }
   1653 
   1654 
   1655 /* end of taler-merchant-httpd_get-private-kyc.c */