merchant

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

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


      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     (POF_TEXT == kc->format)
    603     ? GNUNET_JSON_pack_string ("interval",
    604                                GNUNET_TIME_relative2s (limit->timeframe,
    605                                                        true))
    606     : GNUNET_JSON_pack_time_rel ("timeframe",
    607                                  limit->timeframe),
    608     TALER_JSON_pack_amount ("threshold",
    609                             &limit->threshold),
    610     GNUNET_JSON_pack_bool ("soft_limit",
    611                            limit->soft_limit)
    612     );
    613   GNUNET_assert (0 ==
    614                  json_array_append_new (limits,
    615                                         jl));
    616 }
    617 
    618 
    619 /**
    620  * Return JSON array with AccountLimit objects giving
    621  * the current limits for this exchange.
    622  *
    623  * @param[in,out] ekr overall request context
    624  */
    625 static json_t *
    626 get_exchange_limits (
    627   struct ExchangeKycRequest *ekr)
    628 {
    629   const struct TALER_EXCHANGE_Keys *keys = ekr->keys;
    630   json_t *limits;
    631 
    632   if (NULL != ekr->jlimits)
    633   {
    634     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    635                 "Returning custom KYC limits\n");
    636     return json_incref (ekr->jlimits);
    637   }
    638   if (NULL == keys)
    639   {
    640     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    641                 "No keys, thus no default KYC limits known\n");
    642     return NULL;
    643   }
    644   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    645               "Returning default KYC limits (%u/%u)\n",
    646               keys->hard_limits_length,
    647               keys->zero_limits_length);
    648   limits = json_array ();
    649   GNUNET_assert (NULL != limits);
    650   for (unsigned int i = 0; i<keys->hard_limits_length; i++)
    651   {
    652     const struct TALER_EXCHANGE_AccountLimit *limit
    653       = &keys->hard_limits[i];
    654 
    655     pack_limit (ekr->kc,
    656                 limit,
    657                 limits);
    658   }
    659   for (unsigned int i = 0; i<keys->zero_limits_length; i++)
    660   {
    661     const struct TALER_EXCHANGE_ZeroLimitedOperation *zlimit
    662       = &keys->zero_limits[i];
    663     json_t *jl;
    664     struct TALER_Amount zero;
    665 
    666     GNUNET_assert (GNUNET_OK ==
    667                    TALER_amount_set_zero (keys->currency,
    668                                           &zero));
    669     jl = GNUNET_JSON_PACK (
    670       TALER_JSON_pack_kycte ("operation_type",
    671                              zlimit->operation_type),
    672       GNUNET_JSON_pack_time_rel ("timeframe",
    673                                  GNUNET_TIME_UNIT_ZERO),
    674       TALER_JSON_pack_amount ("threshold",
    675                               &zero),
    676       GNUNET_JSON_pack_bool ("soft_limit",
    677                              true)
    678       );
    679     GNUNET_assert (0 ==
    680                    json_array_append_new (limits,
    681                                           jl));
    682   }
    683   return limits;
    684 }
    685 
    686 
    687 /**
    688  * Maps @a ekr to a status code for clients to interpret the
    689  * overall result.
    690  *
    691  * @param ekr request summary
    692  * @return status of the KYC state as a string
    693  */
    694 static const char *
    695 map_to_status (const struct ExchangeKycRequest *ekr)
    696 {
    697   if (ekr->no_keys)
    698   {
    699     return "no-exchange-keys";
    700   }
    701   if (TALER_EC_MERCHANT_PRIVATE_ACCOUNT_NOT_ELIGIBLE_FOR_EXCHANGE ==
    702       ekr->last_ec)
    703     return "unsupported-account";
    704   if (ekr->kyc_ok)
    705   {
    706     if (NULL != ekr->jlimits)
    707     {
    708       size_t off;
    709       json_t *limit;
    710       json_array_foreach (ekr->jlimits, off, limit)
    711       {
    712         struct TALER_Amount threshold;
    713         enum TALER_KYCLOGIC_KycTriggerEvent operation_type;
    714         bool soft = false;
    715         struct GNUNET_JSON_Specification spec[] = {
    716           TALER_JSON_spec_kycte ("operation_type",
    717                                  &operation_type),
    718           TALER_JSON_spec_amount_any ("threshold",
    719                                       &threshold),
    720           GNUNET_JSON_spec_mark_optional (
    721             GNUNET_JSON_spec_bool ("soft_limit",
    722                                    &soft),
    723             NULL),
    724           GNUNET_JSON_spec_end ()
    725         };
    726 
    727         if (GNUNET_OK !=
    728             GNUNET_JSON_parse (limit,
    729                                spec,
    730                                NULL, NULL))
    731         {
    732           GNUNET_break (0);
    733           return "merchant-internal-error";
    734         }
    735         if (! TALER_amount_is_zero (&threshold))
    736           continue; /* only care about zero-limits */
    737         if (! soft)
    738           continue; /* only care about soft limits */
    739         if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
    740              (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) ||
    741              (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) )
    742         {
    743           if (! ekr->auth_ok)
    744           {
    745             if (ekr->kyc_auth_conflict)
    746               return "kyc-wire-impossible";
    747             return "kyc-wire-required";
    748           }
    749           return "kyc-required";
    750         }
    751       }
    752     }
    753     if (NULL == ekr->jlimits)
    754     {
    755       /* check default limits */
    756       const struct TALER_EXCHANGE_Keys *keys = ekr->keys;
    757 
    758       for (unsigned int i = 0; i < keys->zero_limits_length; i++)
    759       {
    760         enum TALER_KYCLOGIC_KycTriggerEvent operation_type
    761           = keys->zero_limits[i].operation_type;
    762 
    763         if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
    764              (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) ||
    765              (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) )
    766         {
    767           if (! ekr->auth_ok)
    768           {
    769             if (ekr->kyc_auth_conflict)
    770               return "kyc-wire-impossible";
    771             return "kyc-wire-required";
    772           }
    773           return "kyc-required";
    774         }
    775       }
    776     }
    777     return "ready";
    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   if (ekr->in_aml_review)
    786     return "awaiting-aml-review";
    787   switch (ekr->last_http_status)
    788   {
    789   case 0:
    790     return "exchange-unreachable";
    791   case MHD_HTTP_OK:
    792     /* then we should have kyc_ok */
    793     GNUNET_break (0);
    794     return NULL;
    795   case MHD_HTTP_ACCEPTED:
    796     /* Then KYC is really what  is needed */
    797     return "kyc-required";
    798   case MHD_HTTP_NO_CONTENT:
    799     /* then we should have had kyc_ok! */
    800     GNUNET_break (0);
    801     return NULL;
    802   case MHD_HTTP_FORBIDDEN:
    803     /* then we should have had ! auth_ok */
    804     GNUNET_break (0);
    805     return NULL;
    806   case MHD_HTTP_NOT_FOUND:
    807     /* then we should have had ! auth_ok */
    808     GNUNET_break (0);
    809     return NULL;
    810   case MHD_HTTP_CONFLICT:
    811     /* then we should have had ! auth_ok */
    812     GNUNET_break (0);
    813     return NULL;
    814   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    815     return "exchange-internal-error";
    816   case MHD_HTTP_GATEWAY_TIMEOUT:
    817     return "exchange-gateway-timeout";
    818   default:
    819     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    820                 "Exchange responded with unexpected HTTP status %u to /kyc-check request!\n",
    821                 ekr->last_http_status);
    822     break;
    823   }
    824   return "exchange-status-invalid";
    825 }
    826 
    827 
    828 /**
    829  * Take data from @a ekr to expand our response.
    830  *
    831  * @param ekr exchange we are done inspecting
    832  */
    833 static void
    834 ekr_expand_response (struct ExchangeKycRequest *ekr)
    835 {
    836   const struct KycContext *kc = ekr->kc;
    837   struct TMH_Exchange *e = TMH_EXCHANGES_lookup_exchange (ekr->exchange_url);
    838   const char *status;
    839   const char *q;
    840   char *short_account;
    841 
    842   GNUNET_assert (NULL != e);
    843   status = map_to_status (ekr);
    844   if (NULL == status)
    845   {
    846     GNUNET_break (0);
    847     status = "logic-bug";
    848   }
    849   clear_status (ekr->kc,
    850                 status);
    851   q = strchr (ekr->payto_uri.full_payto,
    852               '?');
    853   if (NULL == q)
    854     short_account = GNUNET_strdup (ekr->payto_uri.full_payto);
    855   else
    856     short_account = GNUNET_strndup (ekr->payto_uri.full_payto,
    857                                     q - ekr->payto_uri.full_payto);
    858   GNUNET_assert (
    859     0 ==
    860     json_array_append_new (
    861       ekr->kc->kycs_data,
    862       GNUNET_JSON_PACK (
    863         (POF_TEXT == kc->format)
    864         ? GNUNET_JSON_pack_string (
    865           "short_payto_uri",
    866           short_account)
    867         : TALER_JSON_pack_full_payto (
    868           "payto_uri",
    869           ekr->payto_uri),
    870         GNUNET_JSON_pack_data_auto (
    871           "h_wire",
    872           &ekr->h_wire),
    873         GNUNET_JSON_pack_string (
    874           "status",
    875           status),
    876         GNUNET_JSON_pack_string (
    877           "exchange_url",
    878           ekr->exchange_url),
    879         GNUNET_JSON_pack_string (
    880           "exchange_currency",
    881           TMH_EXCHANGES_get_currency (e)),
    882         GNUNET_JSON_pack_bool ("no_keys",
    883                                ekr->no_keys),
    884         GNUNET_JSON_pack_bool ("auth_conflict",
    885                                ekr->kyc_auth_conflict),
    886         GNUNET_JSON_pack_uint64 ("exchange_http_status",
    887                                  ekr->last_http_status),
    888         (TALER_EC_NONE == ekr->last_ec)
    889         ? GNUNET_JSON_pack_allow_null (
    890           GNUNET_JSON_pack_string (
    891             "dummy",
    892             NULL))
    893         : GNUNET_JSON_pack_uint64 ("exchange_code",
    894                                    ekr->last_ec),
    895         ekr->auth_ok
    896         ? GNUNET_JSON_pack_data_auto (
    897           "access_token",
    898           &ekr->access_token)
    899         : GNUNET_JSON_pack_allow_null (
    900           GNUNET_JSON_pack_string (
    901             "dummy",
    902             NULL)),
    903         GNUNET_JSON_pack_allow_null (
    904           GNUNET_JSON_pack_array_steal (
    905             "limits",
    906             get_exchange_limits (ekr))),
    907         GNUNET_JSON_pack_allow_null (
    908           GNUNET_JSON_pack_array_incref ("payto_kycauths",
    909                                          ekr->pkaa))
    910         )));
    911   GNUNET_free (short_account);
    912 }
    913 
    914 
    915 /**
    916  * We are done with asynchronous processing, generate the
    917  * response for the @e kc.
    918  *
    919  * @param[in,out] kc KYC context to respond for
    920  */
    921 static void
    922 kc_respond (struct KycContext *kc)
    923 {
    924   if ( (! kc->return_immediately) &&
    925        (! GNUNET_TIME_absolute_is_past (kc->timeout)) )
    926   {
    927     if (GNUNET_NO == kc->suspended)
    928     {
    929       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    930                   "Suspending: long poll target %d not reached\n",
    931                   kc->lpt);
    932       MHD_suspend_connection (kc->connection);
    933       kc->suspended = GNUNET_YES;
    934     }
    935     else
    936     {
    937       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    938                   "Remaining suspended: long poll target %d not reached\n",
    939                   kc->lpt);
    940     }
    941     return;
    942   }
    943   /* All exchange requests done, create final
    944      big response from cumulated replies */
    945   resume_kyc_with_response (kc);
    946 }
    947 
    948 
    949 /**
    950  * We are done with the KYC request @a ekr.  Remove it from the work list and
    951  * check if we are done overall.
    952  *
    953  * @param[in] ekr key request that is done (and will be freed)
    954  */
    955 static void
    956 ekr_finished (struct ExchangeKycRequest *ekr)
    957 {
    958   struct KycContext *kc = ekr->kc;
    959 
    960   ekr_expand_response (ekr);
    961   ekr_cleanup (ekr);
    962   if (NULL != kc->exchange_pending_head)
    963     return; /* wait for more */
    964   kc_respond (kc);
    965 }
    966 
    967 
    968 /**
    969  * Figure out which exchange accounts from @a keys could
    970  * be used for a KYC auth wire transfer from the account
    971  * that @a ekr is checking. Will set the "pkaa" array
    972  * in @a ekr.
    973  *
    974  * @param[in,out] ekr request we are processing
    975  */
    976 static void
    977 determine_eligible_accounts (
    978   struct ExchangeKycRequest *ekr)
    979 {
    980   struct KycContext *kc = ekr->kc;
    981   const struct TALER_EXCHANGE_Keys *keys = ekr->keys;
    982   struct TALER_Amount kyc_amount;
    983   char *merchant_pub_str;
    984   struct TALER_NormalizedPayto np;
    985 
    986   ekr->pkaa = json_array ();
    987   GNUNET_assert (NULL != ekr->pkaa);
    988   {
    989     const struct TALER_EXCHANGE_GlobalFee *gf;
    990 
    991     gf = TALER_EXCHANGE_get_global_fee (keys,
    992                                         GNUNET_TIME_timestamp_get ());
    993     if (NULL == gf)
    994     {
    995       GNUNET_assert (GNUNET_OK ==
    996                      TALER_amount_set_zero (keys->currency,
    997                                             &kyc_amount));
    998     }
    999     else
   1000     {
   1001       /* FIXME-#9427: history fee should be globally renamed to KYC fee... */
   1002       kyc_amount = gf->fees.history;
   1003     }
   1004   }
   1005 
   1006   merchant_pub_str
   1007     = GNUNET_STRINGS_data_to_string_alloc (
   1008         &kc->mi->merchant_pub,
   1009         sizeof (kc->mi->merchant_pub));
   1010   /* For all accounts of the exchange */
   1011   np = TALER_payto_normalize (ekr->payto_uri);
   1012   for (unsigned int i = 0; i<keys->accounts_len; i++)
   1013   {
   1014     const struct TALER_EXCHANGE_WireAccount *account
   1015       = &keys->accounts[i];
   1016 
   1017     /* KYC auth transfers are never supported with conversion */
   1018     if (NULL != account->conversion_url)
   1019       continue;
   1020     /* filter by source account by credit_restrictions */
   1021     if (GNUNET_YES !=
   1022         TALER_EXCHANGE_test_account_allowed (account,
   1023                                              true, /* credit */
   1024                                              np))
   1025       continue;
   1026     /* exchange account is allowed, add it */
   1027     {
   1028       const char *exchange_account_payto
   1029         = account->fpayto_uri.full_payto;
   1030       char *payto_kycauth;
   1031 
   1032       if (TALER_amount_is_zero (&kyc_amount))
   1033         GNUNET_asprintf (&payto_kycauth,
   1034                          "%s%cmessage=KYC:%s",
   1035                          exchange_account_payto,
   1036                          (NULL == strchr (exchange_account_payto,
   1037                                           '?'))
   1038                          ? '?'
   1039                          : '&',
   1040                          merchant_pub_str);
   1041       else
   1042         GNUNET_asprintf (&payto_kycauth,
   1043                          "%s%camount=%s&message=KYC:%s",
   1044                          exchange_account_payto,
   1045                          (NULL == strchr (exchange_account_payto,
   1046                                           '?'))
   1047                          ? '?'
   1048                          : '&',
   1049                          TALER_amount2s (&kyc_amount),
   1050                          merchant_pub_str);
   1051       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1052                   "Found account %s where KYC auth is possible\n",
   1053                   payto_kycauth);
   1054       GNUNET_assert (0 ==
   1055                      json_array_append_new (ekr->pkaa,
   1056                                             json_string (payto_kycauth)));
   1057       GNUNET_free (payto_kycauth);
   1058     }
   1059   }
   1060   GNUNET_free (np.normalized_payto);
   1061   GNUNET_free (merchant_pub_str);
   1062 }
   1063 
   1064 
   1065 /**
   1066  * Function called with the result of a #TMH_EXCHANGES_keys4exchange()
   1067  * operation.  Runs the KYC check against the exchange.
   1068  *
   1069  * @param cls closure with our `struct ExchangeKycRequest *`
   1070  * @param keys keys of the exchange context
   1071  * @param exchange representation of the exchange
   1072  */
   1073 static void
   1074 kyc_with_exchange (void *cls,
   1075                    struct TALER_EXCHANGE_Keys *keys,
   1076                    struct TMH_Exchange *exchange)
   1077 {
   1078   struct ExchangeKycRequest *ekr = cls;
   1079 
   1080   (void) exchange;
   1081   ekr->fo = NULL;
   1082   if (NULL == keys)
   1083   {
   1084     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1085                 "Failed to download `%skeys`\n",
   1086                 ekr->exchange_url);
   1087     ekr->no_keys = true;
   1088     ekr_finished (ekr);
   1089     return;
   1090   }
   1091   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1092               "Got /keys for `%s'\n",
   1093               ekr->exchange_url);
   1094   ekr->keys = TALER_EXCHANGE_keys_incref (keys);
   1095   if (! ekr->auth_ok)
   1096   {
   1097     determine_eligible_accounts (ekr);
   1098     if (0 == json_array_size (ekr->pkaa))
   1099     {
   1100       /* No KYC auth wire transfers are possible to this exchange from
   1101          our merchant bank account, so we cannot use this account with
   1102          this exchange if it has any KYC requirements! */
   1103       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1104                   "KYC auth to `%s' impossible for merchant account `%s'\n",
   1105                   ekr->exchange_url,
   1106                   ekr->payto_uri.full_payto);
   1107       ekr->kyc_auth_conflict = true;
   1108     }
   1109   }
   1110   ekr_finished (ekr);
   1111 }
   1112 
   1113 
   1114 /**
   1115  * Closure for add_unreachable_status().
   1116  */
   1117 struct UnreachableContext
   1118 {
   1119   /**
   1120    * Where we are building the response.
   1121    */
   1122   struct KycContext *kc;
   1123 
   1124   /**
   1125    * Pointer to our account hash.
   1126    */
   1127   const struct TALER_MerchantWireHashP *h_wire;
   1128 
   1129   /**
   1130    * Bank account for which we have no status from any exchange.
   1131    */
   1132   struct TALER_FullPayto payto_uri;
   1133 
   1134 };
   1135 
   1136 /**
   1137  * Add all trusted exchanges with "unknown" status for the
   1138  * bank account given in the context.
   1139  *
   1140  * @param cls a `struct UnreachableContext`
   1141  * @param url base URL of the exchange
   1142  * @param exchange internal handle for the exchange
   1143  */
   1144 static void
   1145 add_unreachable_status (void *cls,
   1146                         const char *url,
   1147                         const struct TMH_Exchange *exchange)
   1148 {
   1149   struct UnreachableContext *uc = cls;
   1150   struct KycContext *kc = uc->kc;
   1151 
   1152   clear_status (kc,
   1153                 "exchange-unreachable");
   1154   GNUNET_assert (
   1155     0 ==
   1156     json_array_append_new (
   1157       kc->kycs_data,
   1158       GNUNET_JSON_PACK (
   1159         TALER_JSON_pack_full_payto (
   1160           "payto_uri",
   1161           uc->payto_uri),
   1162         GNUNET_JSON_pack_data_auto (
   1163           "h_wire",
   1164           uc->h_wire),
   1165         GNUNET_JSON_pack_string (
   1166           "exchange_currency",
   1167           TMH_EXCHANGES_get_currency (exchange)),
   1168         GNUNET_JSON_pack_string (
   1169           "status",
   1170           "exchange-unreachable"),
   1171         GNUNET_JSON_pack_string (
   1172           "exchange_url",
   1173           url),
   1174         GNUNET_JSON_pack_bool ("no_keys",
   1175                                true),
   1176         GNUNET_JSON_pack_bool ("auth_conflict",
   1177                                false),
   1178         GNUNET_JSON_pack_uint64 ("exchange_http_status",
   1179                                  0)
   1180         )));
   1181 
   1182 }
   1183 
   1184 
   1185 /**
   1186  * Function called from account_kyc_get_status() with KYC status information
   1187  * for this merchant.
   1188  *
   1189  * @param cls our `struct KycContext *`
   1190  * @param h_wire hash of the wire account
   1191  * @param payto_uri payto:// URI of the merchant's bank account
   1192  * @param exchange_url base URL of the exchange for which this is a status
   1193  * @param last_check when did we last get an update on our KYC status from the exchange
   1194  * @param kyc_ok true if we satisfied the KYC requirements
   1195  * @param access_token access token for the KYC SPA, NULL if we cannot access it yet (need KYC auth wire transfer)
   1196  * @param last_http_status last HTTP status from /kyc-check
   1197  * @param last_ec last Taler error code from /kyc-check
   1198  * @param in_aml_review true if the account is pending review
   1199  * @param jlimits JSON array of applicable AccountLimits, or NULL if unknown (like defaults apply)
   1200  */
   1201 static void
   1202 kyc_status_cb (
   1203   void *cls,
   1204   const struct TALER_MerchantWireHashP *h_wire,
   1205   struct TALER_FullPayto payto_uri,
   1206   const char *exchange_url,
   1207   struct GNUNET_TIME_Timestamp last_check,
   1208   bool kyc_ok,
   1209   const struct TALER_AccountAccessTokenP *access_token,
   1210   unsigned int last_http_status,
   1211   enum TALER_ErrorCode last_ec,
   1212   bool in_aml_review,
   1213   const json_t *jlimits)
   1214 {
   1215   struct KycContext *kc = cls;
   1216   struct ExchangeKycRequest *ekr;
   1217 
   1218   if (NULL == exchange_url)
   1219   {
   1220     struct UnreachableContext uc = {
   1221       .kc = kc,
   1222       .h_wire = h_wire,
   1223       .payto_uri = payto_uri
   1224     };
   1225 
   1226     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1227                 "Account has unknown KYC status for all exchanges.\n");
   1228     TMH_exchange_get_trusted (&add_unreachable_status,
   1229                               &uc);
   1230     return;
   1231   }
   1232   if (! TMH_EXCHANGES_check_trusted (exchange_url))
   1233   {
   1234     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1235                 "Skipping exchange `%s': not trusted\n",
   1236                 exchange_url);
   1237     return;
   1238   }
   1239   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1240               "KYC status for `%s' at `%s' is %u/%s/%s/%s\n",
   1241               payto_uri.full_payto,
   1242               exchange_url,
   1243               last_http_status,
   1244               kyc_ok ? "KYC OK" : "KYC NEEDED",
   1245               in_aml_review ? "IN AML REVIEW" : "NO AML REVIEW",
   1246               NULL == jlimits ? "DEFAULT LIMITS" : "CUSTOM LIMITS");
   1247   switch (kc->lpt)
   1248   {
   1249   case TALER_EXCHANGE_KLPT_NONE:
   1250     break;
   1251   case TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER:
   1252     if (NULL != access_token)
   1253       kc->return_immediately = true;
   1254     break;
   1255   case TALER_EXCHANGE_KLPT_INVESTIGATION_DONE:
   1256     if (! in_aml_review)
   1257       kc->return_immediately = true;
   1258     break;
   1259   case TALER_EXCHANGE_KLPT_KYC_OK:
   1260     if (kyc_ok)
   1261       kc->return_immediately = true;
   1262     break;
   1263   }
   1264   ekr = GNUNET_new (struct ExchangeKycRequest);
   1265   GNUNET_CONTAINER_DLL_insert (kc->exchange_pending_head,
   1266                                kc->exchange_pending_tail,
   1267                                ekr);
   1268   ekr->last_http_status = last_http_status;
   1269   ekr->last_ec = last_ec;
   1270   if (NULL != jlimits)
   1271     ekr->jlimits = json_incref ((json_t *) jlimits);
   1272   ekr->h_wire = *h_wire;
   1273   ekr->exchange_url = GNUNET_strdup (exchange_url);
   1274   ekr->payto_uri.full_payto
   1275     = GNUNET_strdup (payto_uri.full_payto);
   1276   ekr->last_check = last_check;
   1277   ekr->kyc_ok = kyc_ok;
   1278   ekr->kc = kc;
   1279   ekr->in_aml_review = in_aml_review;
   1280   ekr->auth_ok = (NULL != access_token);
   1281   if ( (! ekr->auth_ok) ||
   1282        (NULL == ekr->jlimits) )
   1283   {
   1284     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1285                 "Awaiting /keys from `%s'\n",
   1286                 exchange_url);
   1287 
   1288     /* Figure out wire transfer instructions */
   1289     if (GNUNET_NO == kc->suspended)
   1290     {
   1291       MHD_suspend_connection (kc->connection);
   1292       kc->suspended = GNUNET_YES;
   1293     }
   1294     ekr->fo = TMH_EXCHANGES_keys4exchange (
   1295       exchange_url,
   1296       false,
   1297       &kyc_with_exchange,
   1298       ekr);
   1299     if (NULL == ekr->fo)
   1300     {
   1301       GNUNET_break (0);
   1302       ekr_finished (ekr);
   1303       return;
   1304     }
   1305     return;
   1306   }
   1307   ekr->access_token = *access_token;
   1308   ekr_finished (ekr);
   1309 }
   1310 
   1311 
   1312 /**
   1313  * Check the KYC status of an instance.
   1314  *
   1315  * @param mi instance to check KYC status of
   1316  * @param connection the MHD connection to handle
   1317  * @param[in,out] hc context with further information about the request
   1318  * @return MHD result code
   1319  */
   1320 static MHD_RESULT
   1321 get_instances_ID_kyc (
   1322   struct TMH_MerchantInstance *mi,
   1323   struct MHD_Connection *connection,
   1324   struct TMH_HandlerContext *hc)
   1325 {
   1326   struct KycContext *kc = hc->ctx;
   1327 
   1328   if (NULL == kc)
   1329   {
   1330     kc = GNUNET_new (struct KycContext);
   1331     kc->mi = mi;
   1332     hc->ctx = kc;
   1333     hc->cc = &kyc_context_cleanup;
   1334     GNUNET_CONTAINER_DLL_insert (kc_head,
   1335                                  kc_tail,
   1336                                  kc);
   1337     kc->connection = connection;
   1338     kc->hc = hc;
   1339     kc->kycs_data = json_array ();
   1340     GNUNET_assert (NULL != kc->kycs_data);
   1341     TALER_MHD_parse_request_timeout (connection,
   1342                                      &kc->timeout);
   1343     {
   1344       uint64_t num = 0;
   1345       int val;
   1346 
   1347       TALER_MHD_parse_request_number (connection,
   1348                                       "lpt",
   1349                                       &num);
   1350       val = (int) num;
   1351       if ( (val < 0) ||
   1352            (val > TALER_EXCHANGE_KLPT_MAX) )
   1353       {
   1354         /* Protocol violation, but we can be graceful and
   1355            just ignore the long polling! */
   1356         GNUNET_break_op (0);
   1357         val = TALER_EXCHANGE_KLPT_NONE;
   1358       }
   1359       kc->lpt = (enum TALER_EXCHANGE_KycLongPollTarget) val;
   1360     }
   1361     kc->return_immediately
   1362       = (TALER_EXCHANGE_KLPT_NONE == kc->lpt);
   1363     /* process 'exchange_url' argument */
   1364     kc->exchange_url = MHD_lookup_connection_value (
   1365       connection,
   1366       MHD_GET_ARGUMENT_KIND,
   1367       "exchange_url");
   1368     if ( (NULL != kc->exchange_url) &&
   1369          ( (! TALER_url_valid_charset (kc->exchange_url)) ||
   1370            (! TALER_is_web_url (kc->exchange_url)) ) )
   1371     {
   1372       GNUNET_break_op (0);
   1373       return TALER_MHD_reply_with_error (
   1374         connection,
   1375         MHD_HTTP_BAD_REQUEST,
   1376         TALER_EC_GENERIC_PARAMETER_MALFORMED,
   1377         "exchange_url must be a valid HTTP(s) URL");
   1378     }
   1379     kc->lp_status = MHD_lookup_connection_value (
   1380       connection,
   1381       MHD_GET_ARGUMENT_KIND,
   1382       "lp_status");
   1383     kc->lp_not_status = MHD_lookup_connection_value (
   1384       connection,
   1385       MHD_GET_ARGUMENT_KIND,
   1386       "lp_not_status");
   1387     TALER_MHD_parse_request_arg_auto (connection,
   1388                                       "h_wire",
   1389                                       &kc->h_wire,
   1390                                       kc->have_h_wire);
   1391     TALER_MHD_parse_request_arg_auto (connection,
   1392                                       "lp_not_etag",
   1393                                       &kc->lp_not_etag,
   1394                                       kc->have_lp_not_etag);
   1395 
   1396     /* Determine desired output format from Accept header */
   1397     {
   1398       const char *mime;
   1399 
   1400       mime = MHD_lookup_connection_value (connection,
   1401                                           MHD_HEADER_KIND,
   1402                                           MHD_HTTP_HEADER_ACCEPT);
   1403       if (NULL == mime)
   1404         mime = "application/json";
   1405       if (0 == strcmp (mime,
   1406                        "*/*"))
   1407         mime = "application/json";
   1408       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1409                   "KYC status requested for format %s\n",
   1410                   mime);
   1411       if (0 == strcmp (mime,
   1412                        "application/json"))
   1413       {
   1414         kc->format = POF_JSON;
   1415       }
   1416       else if (0 == strcmp (mime,
   1417                             "text/plain"))
   1418       {
   1419         kc->format = POF_TEXT;
   1420       }
   1421 #if FUTURE
   1422       else if (0 == strcmp (mime,
   1423                             "application/pdf"))
   1424       {
   1425         kc->format = POF_PDF;
   1426       }
   1427 #endif
   1428       else
   1429       {
   1430         GNUNET_break_op (0);
   1431         return TALER_MHD_REPLY_JSON_PACK (
   1432           connection,
   1433           MHD_HTTP_NOT_ACCEPTABLE,
   1434           GNUNET_JSON_pack_string ("hint",
   1435                                    mime));
   1436       }
   1437     }
   1438 
   1439     if (! GNUNET_TIME_absolute_is_past (kc->timeout))
   1440     {
   1441       if (kc->have_h_wire)
   1442       {
   1443         struct TALER_MERCHANTDB_MerchantKycStatusChangeEventP ev = {
   1444           .header.size = htons (sizeof (ev)),
   1445           .header.type = htons (
   1446             TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_STATUS_CHANGED
   1447             ),
   1448           .h_wire = kc->h_wire
   1449         };
   1450 
   1451         kc->eh = TMH_db->event_listen (
   1452           TMH_db->cls,
   1453           &ev.header,
   1454           GNUNET_TIME_absolute_get_remaining (kc->timeout),
   1455           &kyc_change_cb,
   1456           kc);
   1457       }
   1458       else
   1459       {
   1460         struct GNUNET_DB_EventHeaderP hdr = {
   1461           .size = htons (sizeof (hdr)),
   1462           .type = htons (TALER_DBEVENT_MERCHANT_KYC_STATUS_CHANGED)
   1463         };
   1464 
   1465         kc->eh = TMH_db->event_listen (
   1466           TMH_db->cls,
   1467           &hdr,
   1468           GNUNET_TIME_absolute_get_remaining (kc->timeout),
   1469           &kyc_change_cb,
   1470           kc);
   1471       }
   1472     } /* end register LISTEN hooks */
   1473   } /* end 1st time initialization */
   1474 
   1475   if (GNUNET_SYSERR == kc->suspended)
   1476     return MHD_NO; /* during shutdown, we don't generate any more replies */
   1477   GNUNET_assert (GNUNET_NO == kc->suspended);
   1478 
   1479   if (NULL != kc->response)
   1480     return MHD_queue_response (connection,
   1481                                kc->response_code,
   1482                                kc->response);
   1483 
   1484   /* Check our database */
   1485   {
   1486     enum GNUNET_DB_QueryStatus qs;
   1487 
   1488     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1489                 "Checking KYC status for %s (%d/%s)\n",
   1490                 mi->settings.id,
   1491                 kc->have_h_wire,
   1492                 kc->exchange_url);
   1493     /* We may run repeatedly due to long-polling; clear data
   1494        from previous runs first */
   1495     GNUNET_break (0 ==
   1496                   json_array_clear (kc->kycs_data));
   1497     qs = TMH_db->account_kyc_get_status (
   1498       TMH_db->cls,
   1499       mi->settings.id,
   1500       kc->have_h_wire
   1501       ? &kc->h_wire
   1502       : NULL,
   1503       kc->exchange_url,
   1504       &kyc_status_cb,
   1505       kc);
   1506     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1507                 "account_kyc_get_status returned %d records\n",
   1508                 (int) qs);
   1509     switch (qs)
   1510     {
   1511     case GNUNET_DB_STATUS_HARD_ERROR:
   1512     case GNUNET_DB_STATUS_SOFT_ERROR:
   1513       /* Database error */
   1514       GNUNET_break (0);
   1515       if (GNUNET_YES == kc->suspended)
   1516       {
   1517         /* must have suspended before DB error, resume! */
   1518         MHD_resume_connection (connection);
   1519         kc->suspended = GNUNET_NO;
   1520       }
   1521       return TALER_MHD_reply_with_ec (
   1522         connection,
   1523         TALER_EC_GENERIC_DB_FETCH_FAILED,
   1524         "account_kyc_get_status");
   1525     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1526       {
   1527         /* We use an Etag of all zeros for the 204 status code */
   1528         static struct GNUNET_ShortHashCode zero_etag;
   1529 
   1530         /* no matching accounts, could not have suspended */
   1531         GNUNET_assert (GNUNET_NO == kc->suspended);
   1532         if (kc->have_lp_not_etag &&
   1533             (0 == GNUNET_memcmp (&zero_etag,
   1534                                  &kc->lp_not_etag)) &&
   1535             (! GNUNET_TIME_absolute_is_past (kc->timeout)) )
   1536         {
   1537           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1538                       "No matching accounts, suspending to wait for this to change\n");
   1539           MHD_suspend_connection (kc->connection);
   1540           kc->suspended = GNUNET_YES;
   1541           return MHD_YES;
   1542         }
   1543         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1544                     "No matching accounts, returning empty response\n");
   1545         kc->response_code = MHD_HTTP_NO_CONTENT;
   1546         kc->response = MHD_create_response_from_buffer_static (0,
   1547                                                                NULL);
   1548         TALER_MHD_add_global_headers (kc->response,
   1549                                       false);
   1550         {
   1551           char *etag;
   1552 
   1553           etag = GNUNET_STRINGS_data_to_string_alloc (&zero_etag,
   1554                                                       sizeof (zero_etag));
   1555           GNUNET_break (MHD_YES ==
   1556                         MHD_add_response_header (kc->response,
   1557                                                  MHD_HTTP_HEADER_ETAG,
   1558                                                  etag));
   1559           GNUNET_free (etag);
   1560         }
   1561         return MHD_queue_response (connection,
   1562                                    kc->response_code,
   1563                                    kc->response);
   1564       }
   1565     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1566       break;
   1567     } /* end switch (qs) */
   1568   }
   1569 
   1570   /* normal case, but maybe no async activity? In this case,
   1571      respond immediately */
   1572   if (NULL == kc->exchange_pending_head)
   1573   {
   1574     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1575                 "No asynchronous activity, responding now\n");
   1576     kc_respond (kc);
   1577   }
   1578   if (GNUNET_YES == kc->suspended)
   1579   {
   1580     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1581                 "Request handling suspended, waiting for KYC status change\n");
   1582     return MHD_YES;
   1583   }
   1584 
   1585   /* Should have generated a response */
   1586   GNUNET_break (NULL != kc->response);
   1587   return MHD_queue_response (connection,
   1588                              kc->response_code,
   1589                              kc->response);
   1590 }
   1591 
   1592 
   1593 MHD_RESULT
   1594 TMH_private_get_instances_ID_kyc (
   1595   const struct TMH_RequestHandler *rh,
   1596   struct MHD_Connection *connection,
   1597   struct TMH_HandlerContext *hc)
   1598 {
   1599   struct TMH_MerchantInstance *mi = hc->instance;
   1600 
   1601   (void) rh;
   1602   return get_instances_ID_kyc (mi,
   1603                                connection,
   1604                                hc);
   1605 }
   1606 
   1607 
   1608 MHD_RESULT
   1609 TMH_private_get_instances_default_ID_kyc (
   1610   const struct TMH_RequestHandler *rh,
   1611   struct MHD_Connection *connection,
   1612   struct TMH_HandlerContext *hc)
   1613 {
   1614   struct TMH_MerchantInstance *mi;
   1615 
   1616   (void) rh;
   1617   mi = TMH_lookup_instance (hc->infix);
   1618   if (NULL == mi)
   1619   {
   1620     return TALER_MHD_reply_with_error (
   1621       connection,
   1622       MHD_HTTP_NOT_FOUND,
   1623       TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN,
   1624       hc->infix);
   1625   }
   1626   return get_instances_ID_kyc (mi,
   1627                                connection,
   1628                                hc);
   1629 }
   1630 
   1631 
   1632 /* end of taler-merchant-httpd_get-private-kyc.c */