LCOV - code coverage report
Current view: top level - lib - exchange_api_post-management-wire.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 62.6 % 123 77
Test Date: 2026-03-10 12:10:57 Functions: 100.0 % 5 5

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2015-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 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 General Public License along with
      14              :   TALER; see the file COPYING.  If not, see
      15              :   <http://www.gnu.org/licenses/>
      16              : */
      17              : /**
      18              :  * @file lib/exchange_api_post-management-wire.c
      19              :  * @brief functions to enable an exchange wire method / bank account
      20              :  * @author Christian Grothoff
      21              :  */
      22              : #include "taler/platform.h"
      23              : #include "taler/taler_json_lib.h"
      24              : #include <gnunet/gnunet_curl_lib.h>
      25              : #include <microhttpd.h>
      26              : #include "taler/taler_exchange_service.h"
      27              : #include "taler/taler-exchange/post-management-wire.h"
      28              : #include "exchange_api_curl_defaults.h"
      29              : #include "taler/taler_signatures.h"
      30              : #include "taler/taler_curl_lib.h"
      31              : 
      32              : 
      33              : struct TALER_EXCHANGE_PostManagementWireHandle
      34              : {
      35              : 
      36              :   /**
      37              :    * The base URL for this request.
      38              :    */
      39              :   char *base_url;
      40              : 
      41              :   /**
      42              :    * The full URL for this request, set during _start.
      43              :    */
      44              :   char *url;
      45              : 
      46              :   /**
      47              :    * Minor context that holds body and headers.
      48              :    */
      49              :   struct TALER_CURL_PostContext post_ctx;
      50              : 
      51              :   /**
      52              :    * Handle for the request.
      53              :    */
      54              :   struct GNUNET_CURL_Job *job;
      55              : 
      56              :   /**
      57              :    * Function to call with the result.
      58              :    */
      59              :   TALER_EXCHANGE_PostManagementWireCallback cb;
      60              : 
      61              :   /**
      62              :    * Closure for @a cb.
      63              :    */
      64              :   TALER_EXCHANGE_POST_MANAGEMENT_WIRE_RESULT_CLOSURE *cb_cls;
      65              : 
      66              :   /**
      67              :    * Reference to the execution context.
      68              :    */
      69              :   struct GNUNET_CURL_Context *ctx;
      70              : 
      71              :   /**
      72              :    * Payto URI of the exchange's bank account.
      73              :    */
      74              :   char *payto_uri_str;
      75              : 
      76              :   /**
      77              :    * URL of the conversion service, or NULL.
      78              :    */
      79              :   char *conversion_url;
      80              : 
      81              :   /**
      82              :    * JSON encoding of debit restrictions (we hold a reference).
      83              :    */
      84              :   json_t *debit_restrictions;
      85              : 
      86              :   /**
      87              :    * JSON encoding of credit restrictions (we hold a reference).
      88              :    */
      89              :   json_t *credit_restrictions;
      90              : 
      91              :   /**
      92              :    * When was this decided?
      93              :    */
      94              :   struct GNUNET_TIME_Timestamp validity_start;
      95              : 
      96              :   /**
      97              :    * Signature affirming the wire addition.
      98              :    */
      99              :   struct TALER_MasterSignatureP master_sig1;
     100              : 
     101              :   /**
     102              :    * Signature affirming the validity of the account for clients.
     103              :    */
     104              :   struct TALER_MasterSignatureP master_sig2;
     105              : 
     106              :   /**
     107              :    * Label to use when showing the account to users (or NULL).
     108              :    */
     109              :   char *bank_label;
     110              : 
     111              :   /**
     112              :    * Priority for ordering the bank accounts.
     113              :    */
     114              :   int64_t priority;
     115              : 
     116              : };
     117              : 
     118              : 
     119              : /**
     120              :  * Function called when we're done processing the
     121              :  * HTTP POST /management/wire request.
     122              :  *
     123              :  * @param cls the `struct TALER_EXCHANGE_PostManagementWireHandle`
     124              :  * @param response_code HTTP response code, 0 on error
     125              :  * @param response response body, NULL if not in JSON
     126              :  */
     127              : static void
     128           25 : handle_wire_finished (void *cls,
     129              :                       long response_code,
     130              :                       const void *response)
     131              : {
     132           25 :   struct TALER_EXCHANGE_PostManagementWireHandle *pmwh = cls;
     133           25 :   const json_t *json = response;
     134           25 :   struct TALER_EXCHANGE_PostManagementWireResponse res = {
     135           25 :     .hr.http_status = (unsigned int) response_code,
     136              :     .hr.reply = json
     137              :   };
     138              : 
     139           25 :   pmwh->job = NULL;
     140           25 :   switch (response_code)
     141              :   {
     142            0 :   case 0:
     143              :     /* no reply */
     144            0 :     res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     145            0 :     res.hr.hint = "server offline?";
     146            0 :     break;
     147           23 :   case MHD_HTTP_NO_CONTENT:
     148           23 :     break;
     149            2 :   case MHD_HTTP_FORBIDDEN:
     150            2 :     res.hr.ec = TALER_JSON_get_error_code (json);
     151            2 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     152            2 :     break;
     153            0 :   case MHD_HTTP_NOT_FOUND:
     154            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     155              :                 "Server did not find handler at `%s'. Did you configure the correct exchange base URL?\n",
     156              :                 pmwh->url);
     157            0 :     if (NULL != json)
     158              :     {
     159            0 :       res.hr.ec = TALER_JSON_get_error_code (json);
     160            0 :       res.hr.hint = TALER_JSON_get_error_hint (json);
     161              :     }
     162              :     else
     163              :     {
     164            0 :       res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     165            0 :       res.hr.hint = TALER_ErrorCode_get_hint (res.hr.ec);
     166              :     }
     167            0 :     break;
     168            0 :   case MHD_HTTP_CONFLICT:
     169            0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     170            0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     171            0 :     break;
     172            0 :   default:
     173              :     /* unexpected response code */
     174            0 :     GNUNET_break_op (0);
     175            0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     176            0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     177            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     178              :                 "Unexpected response code %u/%d for exchange management enable wire\n",
     179              :                 (unsigned int) response_code,
     180              :                 (int) res.hr.ec);
     181            0 :     break;
     182              :   }
     183           25 :   if (NULL != pmwh->cb)
     184              :   {
     185           25 :     pmwh->cb (pmwh->cb_cls,
     186              :               &res);
     187           25 :     pmwh->cb = NULL;
     188              :   }
     189           25 :   TALER_EXCHANGE_post_management_wire_cancel (pmwh);
     190           25 : }
     191              : 
     192              : 
     193              : struct TALER_EXCHANGE_PostManagementWireHandle *
     194           25 : TALER_EXCHANGE_post_management_wire_create (
     195              :   struct GNUNET_CURL_Context *ctx,
     196              :   const char *url,
     197              :   const struct TALER_FullPayto payto_uri,
     198              :   const char *conversion_url,
     199              :   const json_t *debit_restrictions,
     200              :   const json_t *credit_restrictions,
     201              :   struct GNUNET_TIME_Timestamp validity_start,
     202              :   const struct TALER_MasterSignatureP *master_sig1,
     203              :   const struct TALER_MasterSignatureP *master_sig2)
     204              : {
     205              :   struct TALER_EXCHANGE_PostManagementWireHandle *pmwh;
     206              :   char *msg;
     207              : 
     208           25 :   msg = TALER_payto_validate (payto_uri);
     209           25 :   if (NULL != msg)
     210              :   {
     211            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     212              :                 "payto URI is malformed: %s\n",
     213              :                 msg);
     214            0 :     GNUNET_free (msg);
     215            0 :     return NULL;
     216              :   }
     217           25 :   pmwh = GNUNET_new (struct TALER_EXCHANGE_PostManagementWireHandle);
     218           25 :   pmwh->ctx = ctx;
     219           25 :   pmwh->base_url = GNUNET_strdup (url);
     220           25 :   pmwh->payto_uri_str = GNUNET_strdup (payto_uri.full_payto);
     221           25 :   pmwh->conversion_url = (NULL != conversion_url)
     222            0 :     ? GNUNET_strdup (conversion_url)
     223           25 :     : NULL;
     224           25 :   pmwh->debit_restrictions = json_incref ((json_t *) debit_restrictions);
     225           25 :   pmwh->credit_restrictions = json_incref ((json_t *) credit_restrictions);
     226           25 :   pmwh->validity_start = validity_start;
     227           25 :   pmwh->master_sig1 = *master_sig1;
     228           25 :   pmwh->master_sig2 = *master_sig2;
     229           25 :   return pmwh;
     230              : }
     231              : 
     232              : 
     233              : enum GNUNET_GenericReturnValue
     234           17 : TALER_EXCHANGE_post_management_wire_set_options_ (
     235              :   struct TALER_EXCHANGE_PostManagementWireHandle *pmwh,
     236              :   unsigned int num_options,
     237              :   const struct TALER_EXCHANGE_PostManagementWireOptionValue options[])
     238              : {
     239           51 :   for (unsigned int i = 0; i < num_options; i++)
     240              :   {
     241           51 :     const struct TALER_EXCHANGE_PostManagementWireOptionValue *opt
     242           51 :       = &options[i];
     243              : 
     244           51 :     switch (opt->option)
     245              :     {
     246           17 :     case TALER_EXCHANGE_POST_MANAGEMENT_WIRE_OPTION_END:
     247           17 :       return GNUNET_OK;
     248           17 :     case TALER_EXCHANGE_POST_MANAGEMENT_WIRE_OPTION_BANK_LABEL:
     249           17 :       GNUNET_free (pmwh->bank_label);
     250           34 :       pmwh->bank_label = (NULL != opt->details.bank_label)
     251            0 :         ? GNUNET_strdup (opt->details.bank_label)
     252           17 :         : NULL;
     253           17 :       break;
     254           17 :     case TALER_EXCHANGE_POST_MANAGEMENT_WIRE_OPTION_PRIORITY:
     255           17 :       pmwh->priority = opt->details.priority;
     256           17 :       break;
     257            0 :     default:
     258            0 :       GNUNET_break (0);
     259            0 :       return GNUNET_SYSERR;
     260              :     }
     261              :   }
     262            0 :   return GNUNET_OK;
     263              : }
     264              : 
     265              : 
     266              : enum TALER_ErrorCode
     267           25 : TALER_EXCHANGE_post_management_wire_start (
     268              :   struct TALER_EXCHANGE_PostManagementWireHandle *pmwh,
     269              :   TALER_EXCHANGE_PostManagementWireCallback cb,
     270              :   TALER_EXCHANGE_POST_MANAGEMENT_WIRE_RESULT_CLOSURE *cb_cls)
     271              : {
     272              :   CURL *eh;
     273              :   json_t *body;
     274           25 :   struct TALER_FullPayto payto_uri = {
     275           25 :     .full_payto = pmwh->payto_uri_str
     276              :   };
     277              : 
     278           25 :   pmwh->cb = cb;
     279           25 :   pmwh->cb_cls = cb_cls;
     280           25 :   pmwh->url = TALER_url_join (pmwh->base_url,
     281              :                               "management/wire",
     282              :                               NULL);
     283           25 :   if (NULL == pmwh->url)
     284              :   {
     285            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     286              :                 "Could not construct request URL.\n");
     287            0 :     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
     288              :   }
     289           25 :   body = GNUNET_JSON_PACK (
     290              :     TALER_JSON_pack_full_payto ("payto_uri",
     291              :                                 payto_uri),
     292              :     GNUNET_JSON_pack_array_incref ("debit_restrictions",
     293              :                                    pmwh->debit_restrictions),
     294              :     GNUNET_JSON_pack_array_incref ("credit_restrictions",
     295              :                                    pmwh->credit_restrictions),
     296              :     GNUNET_JSON_pack_allow_null (
     297              :       GNUNET_JSON_pack_string ("conversion_url",
     298              :                                pmwh->conversion_url)),
     299              :     GNUNET_JSON_pack_allow_null (
     300              :       GNUNET_JSON_pack_string ("bank_label",
     301              :                                pmwh->bank_label)),
     302              :     GNUNET_JSON_pack_int64 ("priority",
     303              :                             pmwh->priority),
     304              :     GNUNET_JSON_pack_data_auto ("master_sig_add",
     305              :                                 &pmwh->master_sig1),
     306              :     GNUNET_JSON_pack_data_auto ("master_sig_wire",
     307              :                                 &pmwh->master_sig2),
     308              :     GNUNET_JSON_pack_timestamp ("validity_start",
     309              :                                 pmwh->validity_start));
     310           25 :   eh = TALER_EXCHANGE_curl_easy_get_ (pmwh->url);
     311           50 :   if ( (NULL == eh) ||
     312              :        (GNUNET_OK !=
     313           25 :         TALER_curl_easy_post (&pmwh->post_ctx,
     314              :                               eh,
     315              :                               body)) )
     316              :   {
     317            0 :     GNUNET_break (0);
     318            0 :     if (NULL != eh)
     319            0 :       curl_easy_cleanup (eh);
     320            0 :     json_decref (body);
     321            0 :     GNUNET_free (pmwh->url);
     322            0 :     pmwh->url = NULL;
     323            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     324              :   }
     325           25 :   json_decref (body);
     326           25 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     327              :               "Requesting URL '%s'\n",
     328              :               pmwh->url);
     329           50 :   pmwh->job = GNUNET_CURL_job_add2 (pmwh->ctx,
     330              :                                     eh,
     331           25 :                                     pmwh->post_ctx.headers,
     332              :                                     &handle_wire_finished,
     333              :                                     pmwh);
     334           25 :   if (NULL == pmwh->job)
     335              :   {
     336            0 :     TALER_curl_easy_post_finished (&pmwh->post_ctx);
     337            0 :     GNUNET_free (pmwh->url);
     338            0 :     pmwh->url = NULL;
     339            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     340              :   }
     341           25 :   return TALER_EC_NONE;
     342              : }
     343              : 
     344              : 
     345              : void
     346           25 : TALER_EXCHANGE_post_management_wire_cancel (
     347              :   struct TALER_EXCHANGE_PostManagementWireHandle *pmwh)
     348              : {
     349           25 :   if (NULL != pmwh->job)
     350              :   {
     351            0 :     GNUNET_CURL_job_cancel (pmwh->job);
     352            0 :     pmwh->job = NULL;
     353              :   }
     354           25 :   TALER_curl_easy_post_finished (&pmwh->post_ctx);
     355           25 :   json_decref (pmwh->debit_restrictions);
     356           25 :   json_decref (pmwh->credit_restrictions);
     357           25 :   GNUNET_free (pmwh->payto_uri_str);
     358           25 :   GNUNET_free (pmwh->conversion_url);
     359           25 :   GNUNET_free (pmwh->bank_label);
     360           25 :   GNUNET_free (pmwh->url);
     361           25 :   GNUNET_free (pmwh->base_url);
     362           25 :   GNUNET_free (pmwh);
     363           25 : }
     364              : 
     365              : 
     366              : /* end of exchange_api_post-management-wire.c */
        

Generated by: LCOV version 2.0-1