merchant

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

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


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