merchant

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

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


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