exchange

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

exchange_api_delete-purses-PURSE_PUB.c (7761B)


      1 /*
      2    This file is part of TALER
      3    Copyright (C) 2022-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_delete-purses-PURSE_PUB.c
     19  * @brief Implementation of the client to delete a purse
     20  * @author Christian Grothoff
     21  */
     22 #include <jansson.h>
     23 #include <microhttpd.h> /* just for HTTP status codes */
     24 #include <gnunet/gnunet_util_lib.h>
     25 #include <gnunet/gnunet_json_lib.h>
     26 #include <gnunet/gnunet_curl_lib.h>
     27 #include "taler/taler_json_lib.h"
     28 #include "exchange_api_handle.h"
     29 #include "exchange_api_common.h"
     30 #include "exchange_api_curl_defaults.h"
     31 
     32 
     33 /**
     34  * @brief A purse delete handle
     35  */
     36 struct TALER_EXCHANGE_DeletePursesHandle
     37 {
     38 
     39   /**
     40    * The base url for this request.
     41    */
     42   char *base_url;
     43 
     44   /**
     45    * The full url for this request, set during _start.
     46    */
     47   char *url;
     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_DeletePursesCallback cb;
     58 
     59   /**
     60    * Closure for @a cb.
     61    */
     62   TALER_EXCHANGE_DELETE_PURSES_RESULT_CLOSURE *cb_cls;
     63 
     64   /**
     65    * Reference to the execution context.
     66    */
     67   struct GNUNET_CURL_Context *ctx;
     68 
     69   /**
     70    * Header with the purse_sig.
     71    */
     72   struct curl_slist *xhdr;
     73 
     74   /**
     75    * Public key of the purse (derived from private key in _create).
     76    */
     77   struct TALER_PurseContractPublicKeyP purse_pub;
     78 };
     79 
     80 
     81 /**
     82  * Function called when we're done processing the
     83  * HTTP DELETE /purse/$PID request.
     84  *
     85  * @param cls the `struct TALER_EXCHANGE_DeletePursesHandle`
     86  * @param response_code HTTP response code, 0 on error
     87  * @param response parsed JSON result, NULL on error
     88  */
     89 static void
     90 handle_purse_delete_finished (void *cls,
     91                               long response_code,
     92                               const void *response)
     93 {
     94   struct TALER_EXCHANGE_DeletePursesHandle *dph = cls;
     95   const json_t *j = response;
     96   struct TALER_EXCHANGE_DeletePursesResponse dr = {
     97     .hr.reply = j,
     98     .hr.http_status = (unsigned int) response_code
     99   };
    100 
    101   dph->job = NULL;
    102   switch (response_code)
    103   {
    104   case 0:
    105     dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    106     break;
    107   case MHD_HTTP_NO_CONTENT:
    108     break;
    109   case MHD_HTTP_BAD_REQUEST:
    110     /* This should never happen, either us or the exchange is buggy
    111        (or API version conflict); just pass JSON reply to the application */
    112     dr.hr.ec = TALER_JSON_get_error_code (j);
    113     dr.hr.hint = TALER_JSON_get_error_hint (j);
    114     break;
    115   case MHD_HTTP_FORBIDDEN:
    116     dr.hr.ec = TALER_JSON_get_error_code (j);
    117     dr.hr.hint = TALER_JSON_get_error_hint (j);
    118     /* Nothing really to verify, exchange says one of the signatures is
    119        invalid; as we checked them, this should never happen, we
    120        should pass the JSON reply to the application */
    121     break;
    122   case MHD_HTTP_NOT_FOUND:
    123     dr.hr.ec = TALER_JSON_get_error_code (j);
    124     dr.hr.hint = TALER_JSON_get_error_hint (j);
    125     /* Nothing really to verify, this should never
    126        happen, we should pass the JSON reply to the application */
    127     break;
    128   case MHD_HTTP_CONFLICT:
    129     dr.hr.ec = TALER_JSON_get_error_code (j);
    130     dr.hr.hint = TALER_JSON_get_error_hint (j);
    131     break;
    132   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    133     dr.hr.ec = TALER_JSON_get_error_code (j);
    134     dr.hr.hint = TALER_JSON_get_error_hint (j);
    135     /* Server had an internal issue; we should retry, but this API
    136        leaves this to the application */
    137     break;
    138   default:
    139     /* unexpected response code */
    140     dr.hr.ec = TALER_JSON_get_error_code (j);
    141     dr.hr.hint = TALER_JSON_get_error_hint (j);
    142     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    143                 "Unexpected response code %u/%d for exchange purse delete\n",
    144                 (unsigned int) response_code,
    145                 dr.hr.ec);
    146     GNUNET_break_op (0);
    147     break;
    148   }
    149   dph->cb (dph->cb_cls,
    150            &dr);
    151   TALER_EXCHANGE_delete_purses_cancel (dph);
    152 }
    153 
    154 
    155 struct TALER_EXCHANGE_DeletePursesHandle *
    156 TALER_EXCHANGE_delete_purses_create (
    157   struct GNUNET_CURL_Context *ctx,
    158   const char *url,
    159   const struct TALER_PurseContractPrivateKeyP *purse_priv)
    160 {
    161   struct TALER_EXCHANGE_DeletePursesHandle *dph;
    162   struct TALER_PurseContractSignatureP purse_sig;
    163 
    164   dph = GNUNET_new (struct TALER_EXCHANGE_DeletePursesHandle);
    165   dph->ctx = ctx;
    166   dph->base_url = GNUNET_strdup (url);
    167   GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv->eddsa_priv,
    168                                       &dph->purse_pub.eddsa_pub);
    169   TALER_wallet_purse_delete_sign (purse_priv,
    170                                   &purse_sig);
    171   {
    172     char *delete_str;
    173     char *xhdr;
    174 
    175     delete_str =
    176       GNUNET_STRINGS_data_to_string_alloc (&purse_sig,
    177                                            sizeof (purse_sig));
    178     GNUNET_asprintf (&xhdr,
    179                      "Taler-Purse-Signature: %s",
    180                      delete_str);
    181     GNUNET_free (delete_str);
    182     dph->xhdr = curl_slist_append (NULL,
    183                                    xhdr);
    184     GNUNET_free (xhdr);
    185   }
    186   return dph;
    187 }
    188 
    189 
    190 enum TALER_ErrorCode
    191 TALER_EXCHANGE_delete_purses_start (
    192   struct TALER_EXCHANGE_DeletePursesHandle *dph,
    193   TALER_EXCHANGE_DeletePursesCallback cb,
    194   TALER_EXCHANGE_DELETE_PURSES_RESULT_CLOSURE *cb_cls)
    195 {
    196   CURL *eh;
    197   char arg_str[sizeof (dph->purse_pub) * 2 + 32];
    198 
    199   dph->cb = cb;
    200   dph->cb_cls = cb_cls;
    201   {
    202     char pub_str[sizeof (dph->purse_pub) * 2];
    203     char *end;
    204 
    205     end = GNUNET_STRINGS_data_to_string (&dph->purse_pub,
    206                                          sizeof (dph->purse_pub),
    207                                          pub_str,
    208                                          sizeof (pub_str));
    209     *end = '\0';
    210     GNUNET_snprintf (arg_str,
    211                      sizeof (arg_str),
    212                      "purses/%s",
    213                      pub_str);
    214   }
    215   dph->url = TALER_url_join (dph->base_url,
    216                              arg_str,
    217                              NULL);
    218   if (NULL == dph->url)
    219   {
    220     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    221                 "Could not construct request URL.\n");
    222     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    223   }
    224   eh = TALER_EXCHANGE_curl_easy_get_ (dph->url);
    225   if (NULL == eh)
    226   {
    227     GNUNET_break (0);
    228     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    229   }
    230   GNUNET_assert (CURLE_OK ==
    231                  curl_easy_setopt (eh,
    232                                    CURLOPT_CUSTOMREQUEST,
    233                                    MHD_HTTP_METHOD_DELETE));
    234   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    235               "URL for purse delete: `%s'\n",
    236               dph->url);
    237   dph->job = GNUNET_CURL_job_add2 (dph->ctx,
    238                                    eh,
    239                                    dph->xhdr,
    240                                    &handle_purse_delete_finished,
    241                                    dph);
    242   if (NULL == dph->job)
    243     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    244   return TALER_EC_NONE;
    245 }
    246 
    247 
    248 void
    249 TALER_EXCHANGE_delete_purses_cancel (
    250   struct TALER_EXCHANGE_DeletePursesHandle *dph)
    251 {
    252   if (NULL != dph->job)
    253   {
    254     GNUNET_CURL_job_cancel (dph->job);
    255     dph->job = NULL;
    256   }
    257   curl_slist_free_all (dph->xhdr);
    258   GNUNET_free (dph->url);
    259   GNUNET_free (dph->base_url);
    260   GNUNET_free (dph);
    261 }
    262 
    263 
    264 /* end of exchange_api_delete-purses-PURSE_PUB.c */