LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 56.3 % 254 143
Test Date: 2026-09-04 23:42:01 Functions: 90.9 % 11 10

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   (C) 2026 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it under the
       6              :   terms of the GNU Affero General Public License as published by the Free Software
       7              :   Foundation; either version 3, or (at your option) any later version.
       8              : 
       9              :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10              :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11              :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12              : 
      13              :   You should have received a copy of the GNU Affero General Public License
      14              :   along with TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15              : */
      16              : /**
      17              :  * @file src/backend/taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.c
      18              :  * @brief Handle POST /private/accounts/$H_WIRE/kycauth requests
      19              :  * @author Christian Grothoff
      20              :  */
      21              : #include "platform.h"
      22              : #include <jansson.h>
      23              : #include <microhttpd.h>
      24              : #include <gnunet/gnunet_json_lib.h>
      25              : #include <taler/taler_json_lib.h>
      26              : #include <taler/taler_mhd_lib.h>
      27              : #include <taler/taler_bank_service.h>
      28              : #include "taler-merchant-httpd.h"
      29              : #include "taler-merchant-httpd_exchanges.h"
      30              : #include "taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.h"
      31              : #include "merchant-database/get_account.h"
      32              : #include "taler/taler_util.h"
      33              : 
      34              : 
      35              : /**
      36              :  * Processing phases for a kycauth POST request.
      37              :  */
      38              : enum KycAuthPhase
      39              : {
      40              :   /**
      41              :    * Parse the request body and URL path.
      42              :    */
      43              :   KP_PARSE = 0,
      44              : 
      45              :   /**
      46              :    * Fetch exchange /keys (and optionally register with bank gateway).
      47              :    * The connection is suspended in this phase.
      48              :    */
      49              :   KP_CHECK_EXCHANGES,
      50              : 
      51              :   /**
      52              :    * Return the prepared response to the client.
      53              :    */
      54              :   KP_RETURN_RESPONSE,
      55              : 
      56              :   /**
      57              :    * Return MHD_YES to finish handling.
      58              :    */
      59              :   KP_END_YES,
      60              : 
      61              :   /**
      62              :    * Return MHD_NO to close the connection.
      63              :    */
      64              :   KP_END_NO
      65              : };
      66              : 
      67              : 
      68              : struct ExchangeAccount
      69              : {
      70              : 
      71              :   /**
      72              :    * Payto URI of the exchange, saved from /keys.
      73              :    */
      74              :   struct TALER_FullPayto payto;
      75              : 
      76              :   /**
      77              :    * Pending bank gateway registration handle, or NULL.
      78              :    */
      79              :   struct TALER_BANK_RegistrationHandle *brh;
      80              : 
      81              :   /**
      82              :    * Context we are operating in.
      83              :    */
      84              :   struct KycAuthContext *kac;
      85              : 
      86              :   /**
      87              :    * Transfer subjects to use for the account.
      88              :    */
      89              :   struct TALER_BANK_TransferSubject *subjects;
      90              : 
      91              :   /**
      92              :    * Length of the @e subjects array.
      93              :    */
      94              :   unsigned int num_subjects;
      95              : 
      96              :   /**
      97              :    * Expiration time for the given @e ts.
      98              :    */
      99              :   struct GNUNET_TIME_Timestamp expiration;
     100              : };
     101              : 
     102              : 
     103              : /**
     104              :  * Per-request context for POST /private/accounts/$H_WIRE/kycauth.
     105              :  */
     106              : struct KycAuthContext
     107              : {
     108              : 
     109              :   /**
     110              :    * Kept in doubly-linked list.
     111              :    */
     112              :   struct KycAuthContext *next;
     113              : 
     114              :   /**
     115              :    * Kept in doubly-linked list.
     116              :    */
     117              :   struct KycAuthContext *prev;
     118              : 
     119              :   /**
     120              :    * MHD connection we are handling.
     121              :    */
     122              :   struct MHD_Connection *connection;
     123              : 
     124              :   /**
     125              :    * Handler context for this request.
     126              :    */
     127              :   struct TMH_HandlerContext *hc;
     128              : 
     129              :   /**
     130              :    * Prepared HTTP response to return, or NULL.
     131              :    */
     132              :   struct MHD_Response *response;
     133              : 
     134              :   /**
     135              :    * Exchange URL from the request body.
     136              :    */
     137              :   char *exchange_url;
     138              : 
     139              :   /**
     140              :    * Payto URI of our merchant bank account (from DB).
     141              :    */
     142              :   struct TALER_FullPayto payto_uri;
     143              : 
     144              :   /**
     145              :    * Pending /keys lookup operation with the exchange.
     146              :    */
     147              :   struct TMH_EXCHANGES_KeysOperation *fo;
     148              : 
     149              :   /**
     150              :    * Tiny amount from exchange /keys, used as the transfer amount.
     151              :    */
     152              :   struct TALER_Amount tiny_amount;
     153              : 
     154              :   /**
     155              :    * Array of exchange wire account payto URIs, saved from /keys.
     156              :    * Length is @e exchange_accounts_len.
     157              :    */
     158              :   struct ExchangeAccount *exchange_accounts;
     159              : 
     160              :   /**
     161              :    * Number of entries in @e exchange_accounts.
     162              :    */
     163              :   unsigned int exchange_accounts_len;
     164              : 
     165              :   /**
     166              :    * Number of active registrations in @e exchange_accounts.
     167              :    */
     168              :   unsigned int active_registrations;
     169              : 
     170              :   /**
     171              :    * HTTP status code to send with @e response.
     172              :    * UINT_MAX indicates a hard error (return MHD_NO).
     173              :    */
     174              :   unsigned int response_code;
     175              : 
     176              :   /**
     177              :    * Current processing phase.
     178              :    */
     179              :   enum KycAuthPhase phase;
     180              : 
     181              :   /**
     182              :    * #GNUNET_NO if the connection is not suspended,
     183              :    * #GNUNET_YES if the connection is suspended,
     184              :    * #GNUNET_SYSERR if suspended and being force-resumed during shutdown.
     185              :    */
     186              :   enum GNUNET_GenericReturnValue suspended;
     187              : 
     188              : };
     189              : 
     190              : 
     191              : /**
     192              :  * Head of the doubly-linked list of active kycauth contexts.
     193              :  */
     194              : static struct KycAuthContext *kac_head;
     195              : 
     196              : /**
     197              :  * Tail of the doubly-linked list of active kycauth contexts.
     198              :  */
     199              : static struct KycAuthContext *kac_tail;
     200              : 
     201              : 
     202              : void
     203           20 : TMH_force_kac_resume (void)
     204              : {
     205           20 :   for (struct KycAuthContext *kac = kac_head;
     206           20 :        NULL != kac;
     207            0 :        kac = kac->next)
     208              :   {
     209            0 :     if (NULL != kac->fo)
     210              :     {
     211            0 :       TMH_EXCHANGES_keys4exchange_cancel (kac->fo);
     212            0 :       kac->fo = NULL;
     213              :     }
     214            0 :     if (GNUNET_YES == kac->suspended)
     215              :     {
     216            0 :       kac->suspended = GNUNET_SYSERR;
     217            0 :       MHD_resume_connection (kac->connection);
     218              :     }
     219              :   }
     220           20 : }
     221              : 
     222              : 
     223              : /**
     224              :  * Resume processing of @a kac after an async operation completed.
     225              :  *
     226              :  * @param[in,out] kac context to resume
     227              :  */
     228              : static void
     229            1 : kac_resume (struct KycAuthContext *kac)
     230              : {
     231            1 :   GNUNET_assert (GNUNET_YES == kac->suspended);
     232            1 :   kac->suspended = GNUNET_NO;
     233            1 :   MHD_resume_connection (kac->connection);
     234            1 :   TALER_MHD_daemon_trigger ();
     235            1 : }
     236              : 
     237              : 
     238              : /**
     239              :  * Clean up a kycauth context, freeing all resources.
     240              :  *
     241              :  * @param cls a `struct KycAuthContext` to clean up
     242              :  */
     243              : static void
     244            1 : kac_cleanup (void *cls)
     245              : {
     246            1 :   struct KycAuthContext *kac = cls;
     247              : 
     248            1 :   if (NULL != kac->fo)
     249              :   {
     250            0 :     TMH_EXCHANGES_keys4exchange_cancel (kac->fo);
     251            0 :     kac->fo = NULL;
     252              :   }
     253            1 :   if (NULL != kac->response)
     254              :   {
     255            1 :     MHD_destroy_response (kac->response);
     256            1 :     kac->response = NULL;
     257              :   }
     258            1 :   GNUNET_free (kac->exchange_url);
     259            1 :   GNUNET_free (kac->payto_uri.full_payto);
     260            2 :   for (unsigned int i = 0; i < kac->exchange_accounts_len; i++)
     261              :   {
     262            1 :     struct ExchangeAccount *acc = &kac->exchange_accounts[i];
     263              : 
     264            1 :     if (NULL != acc->brh)
     265              :     {
     266            0 :       TALER_BANK_registration_cancel (acc->brh);
     267            0 :       acc->brh = NULL;
     268              :     }
     269            2 :     for (unsigned int j = 0; j<acc->num_subjects; j++)
     270            1 :       TALER_BANK_transfer_subject_free (&acc->subjects[j]);
     271            1 :     GNUNET_free (acc->subjects);
     272            1 :     GNUNET_free (acc->payto.full_payto);
     273              :   }
     274            1 :   GNUNET_free (kac->exchange_accounts);
     275            1 :   GNUNET_CONTAINER_DLL_remove (kac_head,
     276              :                                kac_tail,
     277              :                                kac);
     278            1 :   GNUNET_free (kac);
     279            1 : }
     280              : 
     281              : 
     282              : /**
     283              :  * Convert a @a ts (transfer subject) to a JSON object.
     284              :  * The resulting object has a "type" field discriminating the format,
     285              :  * matching the JSON format returned by the bank gateway's /registration.
     286              :  *
     287              :  * @param acc general account details
     288              :  * @param ts the specific transfer subject to convert
     289              :  * @return freshly allocated JSON object, or NULL on error
     290              :  */
     291              : static json_t *
     292            1 : kyc_transfer_subject_to_json (const struct ExchangeAccount *acc,
     293              :                               const struct TALER_BANK_TransferSubject *ts)
     294              : {
     295            1 :   struct KycAuthContext *kac = acc->kac;
     296              :   json_t *ret;
     297              : 
     298            1 :   switch (ts->format)
     299              :   {
     300            1 :   case TALER_BANK_SUBJECT_FORMAT_SIMPLE:
     301              :     {
     302            1 :       struct GNUNET_Buffer buf = { 0 };
     303              :       char *subject;
     304              : 
     305            1 :       GNUNET_buffer_write_str (&buf,
     306              :                                "KYC:");
     307            1 :       GNUNET_buffer_write_data_encoded (&buf,
     308            1 :                                         &kac->hc->instance->merchant_pub,
     309              :                                         sizeof (kac->hc->instance->merchant_pub));
     310            1 :       subject = GNUNET_buffer_reap_str (&buf);
     311            1 :       ret = GNUNET_JSON_PACK (
     312              :         GNUNET_JSON_pack_string ("type",
     313              :                                  "SIMPLE"),
     314              :         TALER_JSON_pack_amount ("credit_amount",
     315              :                                 &kac->tiny_amount),
     316              :         GNUNET_JSON_pack_string ("subject",
     317              :                                  subject));
     318            1 :       GNUNET_free (subject);
     319              :     }
     320            1 :     return ret;
     321            0 :   case TALER_BANK_SUBJECT_FORMAT_URI:
     322            0 :     return GNUNET_JSON_PACK (
     323              :       GNUNET_JSON_pack_string ("type",
     324              :                                "URI"),
     325              :       TALER_JSON_pack_amount ("credit_amount",
     326              :                               &kac->tiny_amount),
     327              :       GNUNET_JSON_pack_string ("uri",
     328              :                                ts->details.uri.uri));
     329            0 :   case TALER_BANK_SUBJECT_FORMAT_CH_QR_BILL:
     330            0 :     return GNUNET_JSON_PACK (
     331              :       GNUNET_JSON_pack_string ("type",
     332              :                                "CH_QR_BILL"),
     333              :       TALER_JSON_pack_amount ("credit_amount",
     334              :                               &ts->details.ch_qr_bill.credit_amount),
     335              :       GNUNET_JSON_pack_string ("qr_reference_number",
     336              :                                ts->details.ch_qr_bill.qr_reference_number));
     337              :   }
     338            0 :   GNUNET_break (0);
     339            0 :   return NULL;
     340              : }
     341              : 
     342              : 
     343              : /**
     344              :  * Generate the final "OK" response for the request in @a kac.
     345              :  * Builds the wire_instructions JSON array from the saved exchange accounts
     346              :  * and the given transfer subject.
     347              :  *
     348              :  * @param[in,out] kac request with all the details ready to build a response
     349              :  */
     350              : static void
     351            1 : generate_ok_response (struct KycAuthContext *kac)
     352              : {
     353              :   json_t *arr;
     354              : 
     355            1 :   arr = json_array ();
     356            1 :   GNUNET_assert (NULL != arr);
     357            2 :   for (unsigned int i = 0; i < kac->exchange_accounts_len; i++)
     358              :   {
     359            1 :     const struct ExchangeAccount *acc = &kac->exchange_accounts[i];
     360              :     json_t *subj;
     361              :     json_t *entry;
     362              : 
     363            2 :     for (unsigned int j = 0; j < acc->num_subjects; j++)
     364              :     {
     365            1 :       subj = kyc_transfer_subject_to_json (acc,
     366            1 :                                            &acc->subjects[j]);
     367            1 :       GNUNET_assert (NULL != subj);
     368            1 :       entry = GNUNET_JSON_PACK (
     369              :         TALER_JSON_pack_amount ("amount",
     370              :                                 &kac->tiny_amount),
     371              :         TALER_JSON_pack_full_payto ("target_payto",
     372              :                                     acc->payto),
     373              :         GNUNET_JSON_pack_object_steal ("subject",
     374              :                                        subj),
     375              :         GNUNET_JSON_pack_timestamp ("expiration",
     376              :                                     acc->expiration));
     377            1 :       GNUNET_assert (NULL != entry);
     378            1 :       GNUNET_assert (0 ==
     379              :                      json_array_append_new (arr,
     380              :                                             entry));
     381              :     }
     382              :   }
     383            1 :   kac->response_code = MHD_HTTP_OK;
     384            1 :   kac->response = TALER_MHD_MAKE_JSON_PACK (
     385              :     GNUNET_JSON_pack_array_steal ("wire_instructions",
     386              :                                   arr));
     387            1 :   kac->phase = KP_RETURN_RESPONSE;
     388            1 :   kac_resume (kac);
     389            1 : }
     390              : 
     391              : 
     392              : /**
     393              :  * Callback invoked with the result of the bank gateway /registration request.
     394              :  *
     395              :  * @param cls our `struct KycAuthContext`
     396              :  * @param rr response details
     397              :  */
     398              : static void
     399            0 : registration_cb (void *cls,
     400              :                  const struct TALER_BANK_RegistrationResponse *rr)
     401              : {
     402            0 :   struct ExchangeAccount *acc = cls;
     403            0 :   struct KycAuthContext *kac = acc->kac;
     404              : 
     405            0 :   acc->brh = NULL;
     406            0 :   kac->active_registrations--;
     407            0 :   if (MHD_HTTP_OK != rr->http_status)
     408              :   {
     409            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     410              :                 "Bank gateway registration failed with HTTP status %u\n",
     411              :                 rr->http_status);
     412            0 :     if (NULL == kac->response)
     413              :     {
     414            0 :       kac->response_code = MHD_HTTP_BAD_GATEWAY;
     415            0 :       kac->response = TALER_MHD_make_error (
     416              :         TALER_EC_MERCHANT_POST_ACCOUNTS_KYCAUTH_BANK_GATEWAY_UNREACHABLE,
     417              :         "bank gateway /registration failed");
     418            0 :       kac->phase = KP_RETURN_RESPONSE;
     419            0 :       kac_resume (kac);
     420              :     }
     421            0 :     return;
     422              :   }
     423            0 :   GNUNET_free (acc->subjects);
     424            0 :   acc->num_subjects = rr->details.ok.num_subjects;
     425            0 :   acc->subjects = GNUNET_new_array (acc->num_subjects,
     426              :                                     struct TALER_BANK_TransferSubject);
     427            0 :   for (unsigned int i = 0; i<acc->num_subjects; i++)
     428              :   {
     429            0 :     TALER_BANK_transfer_subject_copy (&acc->subjects[i],
     430            0 :                                       &rr->details.ok.subjects[i]);
     431              :   }
     432            0 :   acc->expiration = rr->details.ok.expiration;
     433            0 :   if (0 != kac->active_registrations)
     434            0 :     return; /* wait for more replies */
     435            0 :   generate_ok_response (kac);
     436              : }
     437              : 
     438              : 
     439              : /**
     440              :  * Callback invoked with the /keys of the selected exchange.
     441              :  *
     442              :  * Saves tiny_amount and exchange account payto URIs from the keys, then
     443              :  * either calls the bank gateway /registration (if wire_transfer_gateway is
     444              :  * present) or directly constructs the SIMPLE-format response.
     445              :  *
     446              :  * @param cls our `struct KycAuthContext`
     447              :  * @param keys the exchange's key material, or NULL on failure
     448              :  * @param exchange internal exchange handle (unused)
     449              :  */
     450              : static void
     451            1 : process_keys_cb (void *cls,
     452              :                  struct TALER_EXCHANGE_Keys *keys,
     453              :                  struct TMH_Exchange *exchange)
     454              : {
     455            1 :   struct KycAuthContext *kac = cls;
     456            1 :   struct TMH_MerchantInstance *mi = kac->hc->instance;
     457              : 
     458              :   (void) exchange;
     459            1 :   kac->fo = NULL;
     460            1 :   if (NULL == keys)
     461              :   {
     462            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     463              :                 "Could not get /keys from exchange `%s'\n",
     464              :                 kac->exchange_url);
     465            0 :     GNUNET_assert (NULL == kac->response);
     466            0 :     kac->response_code = MHD_HTTP_BAD_GATEWAY;
     467            0 :     kac->response = TALER_MHD_make_error (
     468              :       TALER_EC_MERCHANT_POST_ACCOUNTS_KYCAUTH_EXCHANGE_UNREACHABLE,
     469            0 :       kac->exchange_url);
     470            0 :     kac->phase = KP_RETURN_RESPONSE;
     471            0 :     kac_resume (kac);
     472            0 :     return;
     473              :   }
     474            1 :   if (! keys->tiny_amount_available)
     475              :   {
     476            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     477              :                 "Exchange `%s' did not provide tiny_amount in /keys\n",
     478              :                 kac->exchange_url);
     479            0 :     GNUNET_assert (NULL == kac->response);
     480            0 :     kac->response_code = MHD_HTTP_BAD_GATEWAY;
     481            0 :     kac->response = TALER_MHD_make_error (
     482              :       TALER_EC_MERCHANT_POST_ACCOUNTS_EXCHANGE_TOO_OLD,
     483              :       "exchange /keys missing tiny_amount");
     484            0 :     kac->phase = KP_RETURN_RESPONSE;
     485            0 :     kac_resume (kac);
     486            0 :     return;
     487              :   }
     488              : 
     489              :   /* Save tiny_amount and exchange wire accounts from keys */
     490            1 :   kac->tiny_amount = keys->tiny_amount;
     491            1 :   kac->exchange_accounts_len = keys->accounts_len;
     492            1 :   if (0 == keys->accounts_len)
     493              :   {
     494            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     495              :                 "Exchange `%s' did not provide any wire accounts in /keys\n",
     496              :                 kac->exchange_url);
     497            0 :     GNUNET_assert (NULL == kac->response);
     498            0 :     kac->response_code = MHD_HTTP_BAD_GATEWAY;
     499            0 :     kac->response = TALER_MHD_make_error (
     500              :       TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS,
     501              :       "exchange /keys missing wire accounts");
     502            0 :     kac->phase = KP_RETURN_RESPONSE;
     503            0 :     kac_resume (kac);
     504            0 :     return;
     505              :   }
     506              : 
     507              :   kac->exchange_accounts
     508            1 :     = GNUNET_new_array (keys->accounts_len,
     509              :                         struct ExchangeAccount);
     510            2 :   for (unsigned int i = 0; i < keys->accounts_len; i++)
     511              :   {
     512            1 :     struct ExchangeAccount *acc = &kac->exchange_accounts[i];
     513              :     struct TALER_PreparedTransferAuthorizationPrivateKeyP apk;
     514              : 
     515            1 :     GNUNET_CRYPTO_eddsa_key_create (&apk.eddsa_priv);
     516            1 :     acc->kac = kac;
     517              :     acc->payto.full_payto
     518            1 :       = GNUNET_strdup (keys->accounts[i].fpayto_uri.full_payto);
     519            1 :     acc->subjects = GNUNET_new (struct TALER_BANK_TransferSubject);
     520            1 :     acc->num_subjects = 1;
     521            1 :     acc->subjects[0].format = TALER_BANK_SUBJECT_FORMAT_SIMPLE;
     522            1 :     acc->expiration = GNUNET_TIME_UNIT_FOREVER_TS;
     523            1 :     if (NULL == keys->accounts[i].prepared_transfer_url)
     524            1 :       continue;
     525            0 :     acc->brh = TALER_BANK_registration (
     526              :       TMH_curl_ctx,
     527            0 :       keys->accounts[i].prepared_transfer_url,
     528            0 :       &keys->accounts[i].fpayto_uri,
     529            0 :       &kac->tiny_amount,
     530              :       TALER_BANK_REGISTRATION_TYPE_KYC,
     531            0 :       (const union TALER_AccountPublicKeyP *) &mi->merchant_pub,
     532              :       // FIXME: turn this into an option when modernizing the BANK API...
     533              :       &apk,
     534              :       false, /* recurrent */
     535              :       &registration_cb,
     536              :       acc);
     537            0 :     if (NULL == acc->brh)
     538              :     {
     539            0 :       GNUNET_break (0);
     540            0 :       GNUNET_assert (NULL == kac->response);
     541            0 :       kac->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
     542            0 :       kac->response = TALER_MHD_make_error (
     543              :         TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
     544              :         "could not start bank gateway registration");
     545            0 :       kac->phase = KP_RETURN_RESPONSE;
     546            0 :       kac_resume (kac);
     547            0 :       return;
     548              :     }
     549            0 :     kac->active_registrations++;
     550              :   }
     551            1 :   if (0 != kac->active_registrations)
     552            0 :     return;
     553            1 :   generate_ok_response (kac);
     554              : }
     555              : 
     556              : 
     557              : /**
     558              :  * Process the PARSE phase: validate the URL path, parse the request body,
     559              :  * and look up the merchant account in the database.
     560              :  *
     561              :  * @param[in,out] kac context to process
     562              :  */
     563              : static void
     564            1 : phase_parse (struct KycAuthContext *kac)
     565              : {
     566            1 :   const char *h_wire_s = kac->hc->infix;
     567              :   struct TALER_MerchantWireHashP h_wire;
     568              :   const char *exchange_url;
     569              :   enum GNUNET_GenericReturnValue res;
     570              :   struct GNUNET_JSON_Specification spec[] = {
     571            1 :     TALER_JSON_spec_web_url ("exchange_url",
     572              :                              &exchange_url),
     573            1 :     GNUNET_JSON_spec_end ()
     574              :   };
     575              : 
     576            1 :   GNUNET_assert (NULL != h_wire_s);
     577            1 :   if (GNUNET_OK !=
     578            1 :       GNUNET_STRINGS_string_to_data (h_wire_s,
     579              :                                      strlen (h_wire_s),
     580              :                                      &h_wire,
     581              :                                      sizeof (h_wire)))
     582              :   {
     583            0 :     GNUNET_break_op (0);
     584            0 :     kac->response_code = MHD_HTTP_BAD_REQUEST;
     585            0 :     kac->response = TALER_MHD_make_error (
     586              :       TALER_EC_MERCHANT_GENERIC_H_WIRE_MALFORMED,
     587              :       h_wire_s);
     588            0 :     kac->phase = KP_RETURN_RESPONSE;
     589            0 :     return;
     590              :   }
     591              : 
     592            1 :   res = TALER_MHD_parse_json_data (kac->connection,
     593            1 :                                    kac->hc->request_body,
     594              :                                    spec);
     595            1 :   if (GNUNET_OK != res)
     596              :   {
     597            0 :     kac->phase = (GNUNET_NO == res) ? KP_END_YES : KP_END_NO;
     598            0 :     return;
     599              :   }
     600              : 
     601              :   /* Look up the merchant account in the database */
     602              :   {
     603            1 :     struct TALER_MERCHANTDB_AccountDetails ad = { 0 };
     604              :     enum GNUNET_DB_QueryStatus qs;
     605              : 
     606            1 :     qs = TALER_MERCHANTDB_get_account (TMH_db,
     607            1 :                                        kac->hc->instance->settings.id,
     608              :                                        &h_wire,
     609              :                                        &ad);
     610            1 :     if (0 > qs)
     611              :     {
     612            0 :       GNUNET_break (0);
     613            0 :       GNUNET_JSON_parse_free (spec);
     614            0 :       kac->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
     615            0 :       kac->response = TALER_MHD_make_error (
     616              :         TALER_EC_GENERIC_DB_FETCH_FAILED,
     617              :         "get_account");
     618            0 :       kac->phase = KP_RETURN_RESPONSE;
     619            0 :       return;
     620              :     }
     621            1 :     if (0 == qs)
     622              :     {
     623            0 :       GNUNET_JSON_parse_free (spec);
     624            0 :       kac->response_code = MHD_HTTP_NOT_FOUND;
     625            0 :       kac->response = TALER_MHD_make_error (
     626              :         TALER_EC_MERCHANT_GENERIC_ACCOUNT_UNKNOWN,
     627              :         h_wire_s);
     628            0 :       kac->phase = KP_RETURN_RESPONSE;
     629            0 :       return;
     630              :     }
     631            1 :     kac->payto_uri.full_payto = GNUNET_strdup (ad.payto_uri.full_payto);
     632              :     /* Free fields we do not need */
     633            1 :     GNUNET_free (ad.payto_uri.full_payto);
     634            1 :     GNUNET_free (ad.credit_facade_url);
     635            1 :     GNUNET_free (ad.extra_wire_subject_metadata);
     636            1 :     json_decref (ad.credit_facade_credentials);
     637              :   }
     638              : 
     639            1 :   kac->exchange_url = GNUNET_strdup (exchange_url);
     640            1 :   GNUNET_JSON_parse_free (spec);
     641            1 :   kac->phase = KP_CHECK_EXCHANGES;
     642              : }
     643              : 
     644              : 
     645              : /**
     646              :  * Process the CHECK_EXCHANGES phase: start an async /keys fetch from
     647              :  * the requested exchange and suspend the connection.
     648              :  *
     649              :  * @param[in,out] kac context to process
     650              :  */
     651              : static void
     652            1 : phase_check_exchanges (struct KycAuthContext *kac)
     653              : {
     654            1 :   kac->fo = TMH_EXCHANGES_keys4exchange (kac->exchange_url,
     655              :                                          false,
     656              :                                          &process_keys_cb,
     657              :                                          kac);
     658            1 :   if (NULL == kac->fo)
     659              :   {
     660            0 :     GNUNET_break_op (0);
     661            0 :     kac->response_code = MHD_HTTP_BAD_REQUEST;
     662            0 :     kac->response = TALER_MHD_make_error (
     663              :       TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED,
     664            0 :       kac->exchange_url);
     665            0 :     kac->phase = KP_RETURN_RESPONSE;
     666            0 :     return;
     667              :   }
     668            1 :   MHD_suspend_connection (kac->connection);
     669            1 :   kac->suspended = GNUNET_YES;
     670              : }
     671              : 
     672              : 
     673              : /**
     674              :  * Process the RETURN_RESPONSE phase: queue the prepared response into MHD.
     675              :  *
     676              :  * @param[in,out] kac context to process
     677              :  */
     678              : static void
     679            1 : phase_return_response (struct KycAuthContext *kac)
     680              : {
     681              :   enum MHD_Result ret;
     682              : 
     683            1 :   if (UINT_MAX == kac->response_code)
     684              :   {
     685            0 :     GNUNET_break (0);
     686            0 :     kac->phase = KP_END_NO;
     687            0 :     return;
     688              :   }
     689            1 :   GNUNET_assert (0 != kac->response_code);
     690            1 :   ret = MHD_queue_response (kac->connection,
     691              :                             kac->response_code,
     692              :                             kac->response);
     693            1 :   kac->phase = (MHD_YES == ret) ? KP_END_YES : KP_END_NO;
     694              : }
     695              : 
     696              : 
     697              : enum MHD_Result
     698            2 : TMH_private_post_accounts_H_WIRE_kycauth (
     699              :   const struct TMH_RequestHandler *rh,
     700              :   struct MHD_Connection *connection,
     701              :   struct TMH_HandlerContext *hc)
     702              : {
     703            2 :   struct KycAuthContext *kac = hc->ctx;
     704              : 
     705              :   (void) rh;
     706            2 :   GNUNET_assert (NULL != hc->infix);
     707            2 :   if (NULL == kac)
     708              :   {
     709            1 :     kac = GNUNET_new (struct KycAuthContext);
     710            1 :     kac->connection = connection;
     711            1 :     kac->hc = hc;
     712            1 :     hc->ctx = kac;
     713            1 :     hc->cc = &kac_cleanup;
     714            1 :     GNUNET_CONTAINER_DLL_insert (kac_head,
     715              :                                  kac_tail,
     716              :                                  kac);
     717              :   }
     718              : 
     719              :   while (1)
     720              :   {
     721            6 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     722              :                 "Processing POST /private/accounts/$H_WIRE/kycauth"
     723              :                 " in phase %d\n",
     724              :                 (int) kac->phase);
     725            4 :     switch (kac->phase)
     726              :     {
     727            1 :     case KP_PARSE:
     728            1 :       phase_parse (kac);
     729            1 :       break;
     730            1 :     case KP_CHECK_EXCHANGES:
     731            1 :       phase_check_exchanges (kac);
     732            1 :       break;
     733            1 :     case KP_RETURN_RESPONSE:
     734            1 :       phase_return_response (kac);
     735            1 :       break;
     736            1 :     case KP_END_YES:
     737            1 :       return MHD_YES;
     738            0 :     case KP_END_NO:
     739            0 :       return MHD_NO;
     740            0 :     default:
     741            0 :       GNUNET_assert (0);
     742              :       return MHD_NO;
     743              :     }
     744              : 
     745            3 :     switch (kac->suspended)
     746              :     {
     747            0 :     case GNUNET_SYSERR:
     748              :       /* Shutdown in progress */
     749            0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     750              :                   "Processing POST /private/accounts/$H_WIRE/kycauth"
     751              :                   " ends due to shutdown in phase %d\n",
     752              :                   (int) kac->phase);
     753            0 :       return MHD_NO;
     754            2 :     case GNUNET_NO:
     755              :       /* Not suspended, continue with next phase */
     756            2 :       break;
     757            1 :     case GNUNET_YES:
     758            1 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     759              :                   "Processing POST /private/accounts/$H_WIRE/kycauth"
     760              :                   " suspended in phase %d\n",
     761              :                   (int) kac->phase);
     762            1 :       return MHD_YES;
     763              :     }
     764              :   }
     765              :   GNUNET_assert (0);
     766              :   return MHD_YES;
     767              : }
     768              : 
     769              : 
     770              : /* end of taler-merchant-httpd_private-post-accounts-H_WIRE-kycauth.c */
        

Generated by: LCOV version 2.0-1