merchant

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

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


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