merchant

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

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


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