exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

exchange_api_post-management-wire.c (11760B)


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