LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_get-private-kyc.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 65.1 % 559 364
Test Date: 2026-09-11 17:45:24 Functions: 84.6 % 26 22

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

Generated by: LCOV version 2.0-1