LCOV - code coverage report
Current view: top level - lib - exchange_api_post-management-wire.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 73.8 % 145 107
Test Date: 2026-04-04 21:36:01 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              :    * URL of the open banking gateway, or NULL.
      83              :    */
      84              :   char *open_banking_gateway;
      85              : 
      86              :   /**
      87              :    * URL of the wire transfer gateway, or NULL.
      88              :    */
      89              :   char *wire_transfer_gateway;
      90              : 
      91              :   /**
      92              :    * JSON encoding of debit restrictions (we hold a reference).
      93              :    */
      94              :   json_t *debit_restrictions;
      95              : 
      96              :   /**
      97              :    * JSON encoding of credit restrictions (we hold a reference).
      98              :    */
      99              :   json_t *credit_restrictions;
     100              : 
     101              :   /**
     102              :    * When was this decided?
     103              :    */
     104              :   struct GNUNET_TIME_Timestamp validity_start;
     105              : 
     106              :   /**
     107              :    * Signature affirming the wire addition.
     108              :    */
     109              :   struct TALER_MasterSignatureP master_sig1;
     110              : 
     111              :   /**
     112              :    * Signature affirming the validity of the account for clients.
     113              :    */
     114              :   struct TALER_MasterSignatureP master_sig2;
     115              : 
     116              :   /**
     117              :    * Label to use when showing the account to users (or NULL).
     118              :    */
     119              :   char *bank_label;
     120              : 
     121              :   /**
     122              :    * Priority for ordering the bank accounts.
     123              :    */
     124              :   int64_t priority;
     125              : 
     126              : };
     127              : 
     128              : 
     129              : /**
     130              :  * Function called when we're done processing the
     131              :  * HTTP POST /management/wire request.
     132              :  *
     133              :  * @param cls the `struct TALER_EXCHANGE_PostManagementWireHandle`
     134              :  * @param response_code HTTP response code, 0 on error
     135              :  * @param response response body, NULL if not in JSON
     136              :  */
     137              : static void
     138           25 : handle_wire_finished (void *cls,
     139              :                       long response_code,
     140              :                       const void *response)
     141              : {
     142           25 :   struct TALER_EXCHANGE_PostManagementWireHandle *pmwh = cls;
     143           25 :   const json_t *json = response;
     144           25 :   struct TALER_EXCHANGE_PostManagementWireResponse res = {
     145           25 :     .hr.http_status = (unsigned int) response_code,
     146              :     .hr.reply = json
     147              :   };
     148              : 
     149           25 :   pmwh->job = NULL;
     150           25 :   switch (response_code)
     151              :   {
     152            0 :   case 0:
     153              :     /* no reply */
     154            0 :     res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     155            0 :     res.hr.hint = "server offline?";
     156            0 :     break;
     157           23 :   case MHD_HTTP_NO_CONTENT:
     158           23 :     break;
     159            0 :   case MHD_HTTP_BAD_REQUEST:
     160            0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     161            0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     162            0 :     break;
     163            2 :   case MHD_HTTP_FORBIDDEN:
     164            2 :     res.hr.ec = TALER_JSON_get_error_code (json);
     165            2 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     166            2 :     break;
     167            0 :   case MHD_HTTP_CONFLICT:
     168            0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     169            0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     170            0 :     break;
     171            0 :   default:
     172              :     /* unexpected response code */
     173            0 :     GNUNET_break_op (0);
     174            0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     175            0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     176            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     177              :                 "Unexpected response code %u/%d for exchange management enable wire\n",
     178              :                 (unsigned int) response_code,
     179              :                 (int) res.hr.ec);
     180            0 :     break;
     181              :   }
     182           25 :   if (NULL != pmwh->cb)
     183              :   {
     184           25 :     pmwh->cb (pmwh->cb_cls,
     185              :               &res);
     186           25 :     pmwh->cb = NULL;
     187              :   }
     188           25 :   TALER_EXCHANGE_post_management_wire_cancel (pmwh);
     189           25 : }
     190              : 
     191              : 
     192              : struct TALER_EXCHANGE_PostManagementWireHandle *
     193           25 : TALER_EXCHANGE_post_management_wire_create (
     194              :   struct GNUNET_CURL_Context *ctx,
     195              :   const char *url,
     196              :   const struct TALER_FullPayto payto_uri,
     197              :   struct GNUNET_TIME_Timestamp validity_start,
     198              :   const struct TALER_MasterSignatureP *master_sig1,
     199              :   const struct TALER_MasterSignatureP *master_sig2)
     200              : {
     201              :   struct TALER_EXCHANGE_PostManagementWireHandle *pmwh;
     202              :   char *msg;
     203              : 
     204           25 :   msg = TALER_payto_validate (payto_uri);
     205           25 :   if (NULL != msg)
     206              :   {
     207            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     208              :                 "payto URI is malformed: %s\n",
     209              :                 msg);
     210            0 :     GNUNET_free (msg);
     211            0 :     return NULL;
     212              :   }
     213           25 :   pmwh = GNUNET_new (struct TALER_EXCHANGE_PostManagementWireHandle);
     214           25 :   pmwh->ctx = ctx;
     215           25 :   pmwh->base_url = GNUNET_strdup (url);
     216           25 :   pmwh->payto_uri_str = GNUNET_strdup (payto_uri.full_payto);
     217           25 :   pmwh->debit_restrictions = json_array ();
     218           25 :   GNUNET_assert (NULL != pmwh->debit_restrictions);
     219           25 :   pmwh->credit_restrictions = json_array ();
     220           25 :   GNUNET_assert (NULL != pmwh->credit_restrictions);
     221           25 :   pmwh->validity_start = validity_start;
     222           25 :   pmwh->master_sig1 = *master_sig1;
     223           25 :   pmwh->master_sig2 = *master_sig2;
     224           25 :   return pmwh;
     225              : }
     226              : 
     227              : 
     228              : enum GNUNET_GenericReturnValue
     229           25 : TALER_EXCHANGE_post_management_wire_set_options_ (
     230              :   struct TALER_EXCHANGE_PostManagementWireHandle *pmwh,
     231              :   unsigned int num_options,
     232              :   const struct TALER_EXCHANGE_PostManagementWireOptionValue options[])
     233              : {
     234          168 :   for (unsigned int i = 0; i < num_options; i++)
     235              :   {
     236          168 :     const struct TALER_EXCHANGE_PostManagementWireOptionValue *opt
     237          168 :       = &options[i];
     238              : 
     239          168 :     switch (opt->option)
     240              :     {
     241           25 :     case TALER_EXCHANGE_POST_MANAGEMENT_WIRE_OPTION_END:
     242           25 :       return GNUNET_OK;
     243           25 :     case TALER_EXCHANGE_POST_MANAGEMENT_WIRE_OPTION_BANK_LABEL:
     244           25 :       GNUNET_free (pmwh->bank_label);
     245           50 :       pmwh->bank_label = (NULL != opt->details.bank_label)
     246            8 :         ? GNUNET_strdup (opt->details.bank_label)
     247           25 :         : NULL;
     248           25 :       break;
     249           17 :     case TALER_EXCHANGE_POST_MANAGEMENT_WIRE_OPTION_PRIORITY:
     250           17 :       pmwh->priority = opt->details.priority;
     251           17 :       break;
     252           17 :     case TALER_EXCHANGE_POST_MANAGEMENT_WIRE_OPTION_CONVERSION_URL:
     253           17 :       GNUNET_free (pmwh->conversion_url);
     254           34 :       pmwh->conversion_url = (NULL != opt->details.conversion_url)
     255            0 :         ? GNUNET_strdup (opt->details.conversion_url)
     256           17 :         : NULL;
     257           17 :       break;
     258           17 :     case TALER_EXCHANGE_POST_MANAGEMENT_WIRE_OPTION_OPEN_BANKING_GATEWAY:
     259           17 :       GNUNET_free (pmwh->open_banking_gateway);
     260           34 :       pmwh->open_banking_gateway = (NULL != opt->details.open_banking_gateway)
     261            0 :         ? GNUNET_strdup (opt->details.open_banking_gateway)
     262           17 :         : NULL;
     263           17 :       break;
     264           17 :     case TALER_EXCHANGE_POST_MANAGEMENT_WIRE_OPTION_WIRE_TRANSFER_GATEWAY:
     265           17 :       GNUNET_free (pmwh->wire_transfer_gateway);
     266           34 :       pmwh->wire_transfer_gateway = (NULL != opt->details.wire_transfer_gateway)
     267            0 :         ? GNUNET_strdup (opt->details.wire_transfer_gateway)
     268           17 :         : NULL;
     269           17 :       break;
     270           25 :     case TALER_EXCHANGE_POST_MANAGEMENT_WIRE_OPTION_CREDIT_RESTRICTIONS:
     271           25 :       json_decref (pmwh->credit_restrictions);
     272           50 :       pmwh->credit_restrictions = (NULL != opt->details.credit_restrictions)
     273           25 :         ? json_incref ((json_t *) opt->details.credit_restrictions)
     274           25 :         : json_array ();
     275           25 :       break;
     276           25 :     case TALER_EXCHANGE_POST_MANAGEMENT_WIRE_OPTION_DEBIT_RESTRICTIONS:
     277           25 :       json_decref (pmwh->debit_restrictions);
     278           50 :       pmwh->debit_restrictions = (NULL != opt->details.debit_restrictions)
     279           25 :         ? json_incref ((json_t *) opt->details.debit_restrictions)
     280           25 :         : json_array ();
     281           25 :       break;
     282            0 :     default:
     283            0 :       GNUNET_break (0);
     284            0 :       return GNUNET_SYSERR;
     285              :     }
     286              :   }
     287            0 :   return GNUNET_OK;
     288              : }
     289              : 
     290              : 
     291              : enum TALER_ErrorCode
     292           25 : TALER_EXCHANGE_post_management_wire_start (
     293              :   struct TALER_EXCHANGE_PostManagementWireHandle *pmwh,
     294              :   TALER_EXCHANGE_PostManagementWireCallback cb,
     295              :   TALER_EXCHANGE_POST_MANAGEMENT_WIRE_RESULT_CLOSURE *cb_cls)
     296              : {
     297              :   CURL *eh;
     298              :   json_t *body;
     299           25 :   struct TALER_FullPayto payto_uri = {
     300           25 :     .full_payto = pmwh->payto_uri_str
     301              :   };
     302              : 
     303           25 :   pmwh->cb = cb;
     304           25 :   pmwh->cb_cls = cb_cls;
     305           25 :   pmwh->url = TALER_url_join (pmwh->base_url,
     306              :                               "management/wire",
     307              :                               NULL);
     308           25 :   if (NULL == pmwh->url)
     309              :   {
     310            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     311              :                 "Could not construct request URL.\n");
     312            0 :     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
     313              :   }
     314           25 :   body = GNUNET_JSON_PACK (
     315              :     TALER_JSON_pack_full_payto ("payto_uri",
     316              :                                 payto_uri),
     317              :     GNUNET_JSON_pack_array_incref ("debit_restrictions",
     318              :                                    pmwh->debit_restrictions),
     319              :     GNUNET_JSON_pack_array_incref ("credit_restrictions",
     320              :                                    pmwh->credit_restrictions),
     321              :     GNUNET_JSON_pack_allow_null (
     322              :       GNUNET_JSON_pack_string ("conversion_url",
     323              :                                pmwh->conversion_url)),
     324              :     GNUNET_JSON_pack_allow_null (
     325              :       GNUNET_JSON_pack_string ("open_banking_gateway",
     326              :                                pmwh->open_banking_gateway)),
     327              :     GNUNET_JSON_pack_allow_null (
     328              :       GNUNET_JSON_pack_string ("wire_transfer_gateway",
     329              :                                pmwh->wire_transfer_gateway)),
     330              :     GNUNET_JSON_pack_allow_null (
     331              :       GNUNET_JSON_pack_string ("bank_label",
     332              :                                pmwh->bank_label)),
     333              :     GNUNET_JSON_pack_int64 ("priority",
     334              :                             pmwh->priority),
     335              :     GNUNET_JSON_pack_data_auto ("master_sig_add",
     336              :                                 &pmwh->master_sig1),
     337              :     GNUNET_JSON_pack_data_auto ("master_sig_wire",
     338              :                                 &pmwh->master_sig2),
     339              :     GNUNET_JSON_pack_timestamp ("validity_start",
     340              :                                 pmwh->validity_start));
     341           25 :   eh = TALER_EXCHANGE_curl_easy_get_ (pmwh->url);
     342           50 :   if ( (NULL == eh) ||
     343              :        (GNUNET_OK !=
     344           25 :         TALER_curl_easy_post (&pmwh->post_ctx,
     345              :                               eh,
     346              :                               body)) )
     347              :   {
     348            0 :     GNUNET_break (0);
     349            0 :     if (NULL != eh)
     350            0 :       curl_easy_cleanup (eh);
     351            0 :     json_decref (body);
     352            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     353              :   }
     354           25 :   json_decref (body);
     355           25 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     356              :               "Requesting URL '%s'\n",
     357              :               pmwh->url);
     358           50 :   pmwh->job = GNUNET_CURL_job_add2 (pmwh->ctx,
     359              :                                     eh,
     360           25 :                                     pmwh->post_ctx.headers,
     361              :                                     &handle_wire_finished,
     362              :                                     pmwh);
     363           25 :   if (NULL == pmwh->job)
     364            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     365           25 :   return TALER_EC_NONE;
     366              : }
     367              : 
     368              : 
     369              : void
     370           25 : TALER_EXCHANGE_post_management_wire_cancel (
     371              :   struct TALER_EXCHANGE_PostManagementWireHandle *pmwh)
     372              : {
     373           25 :   if (NULL != pmwh->job)
     374              :   {
     375            0 :     GNUNET_CURL_job_cancel (pmwh->job);
     376            0 :     pmwh->job = NULL;
     377              :   }
     378           25 :   TALER_curl_easy_post_finished (&pmwh->post_ctx);
     379           25 :   json_decref (pmwh->debit_restrictions);
     380           25 :   json_decref (pmwh->credit_restrictions);
     381           25 :   GNUNET_free (pmwh->payto_uri_str);
     382           25 :   GNUNET_free (pmwh->conversion_url);
     383           25 :   GNUNET_free (pmwh->open_banking_gateway);
     384           25 :   GNUNET_free (pmwh->wire_transfer_gateway);
     385           25 :   GNUNET_free (pmwh->bank_label);
     386           25 :   GNUNET_free (pmwh->url);
     387           25 :   GNUNET_free (pmwh->base_url);
     388           25 :   GNUNET_free (pmwh);
     389           25 : }
     390              : 
     391              : 
     392              : /* end of exchange_api_post-management-wire.c */
        

Generated by: LCOV version 2.0-1